| author | |
| committer | |
| log | 8c4a2dc1dfe05a67eb9811b8c8291c5541816a99 |
| tree | 9437f16152597b75b6a8b7ec77abbba1252c937d |
| parent | e8c4e79499fbb2a83a0f4fe2cac0d80e5d12a07e |
3 files changed, 743 insertions(+), 713 deletions(-)
lib/std/c.zig+35| ... | ... | @@ -9541,10 +9541,24 @@ pub const CPUFAMILY = darwin.CPUFAMILY; |
| 9541 | 9541 | pub const DB_RECORDTYPE = darwin.DB_RECORDTYPE; |
| 9542 | 9542 | pub const EXC = darwin.EXC; |
| 9543 | 9543 | pub const EXCEPTION = darwin.EXCEPTION; |
| 9544 | pub const MACH_MSG_TYPE = darwin.MACH_MSG_TYPE; | |
| 9545 | pub const MACH_PORT_RIGHT = darwin.MACH_PORT_RIGHT; | |
| 9546 | pub const MACH_TASK_BASIC_INFO = darwin.MACH_TASK_BASIC_INFO; | |
| 9547 | pub const MACH_TASK_BASIC_INFO_COUNT = darwin.MACH_TASK_BASIC_INFO_COUNT; | |
| 9548 | pub const MATTR = darwin.MATTR; | |
| 9544 | 9549 | pub const NSVersionOfRunTimeLibrary = darwin.NSVersionOfRunTimeLibrary; |
| 9545 | 9550 | pub const OPEN_MAX = darwin.OPEN_MAX; |
| 9551 | pub const POSIX_SPAWN = darwin.POSIX_SPAWN; | |
| 9552 | pub const TASK_NULL = darwin.TASK_NULL; | |
| 9553 | pub const TASK_VM_INFO = darwin.TASK_VM_INFO; | |
| 9554 | pub const TASK_VM_INFO_COUNT = darwin.TASK_VM_INFO_COUNT; | |
| 9555 | pub const THREAD_BASIC_INFO = darwin.THREAD_BASIC_INFO; | |
| 9556 | pub const THREAD_BASIC_INFO_COUNT = darwin.THREAD_BASIC_INFO_COUNT; | |
| 9557 | pub const THREAD_IDENTIFIER_INFO_COUNT = darwin.THREAD_IDENTIFIER_INFO_COUNT; | |
| 9558 | pub const THREAD_NULL = darwin.THREAD_NULL; | |
| 9546 | 9559 | pub const THREAD_STATE_NONE = darwin.THREAD_STATE_NONE; |
| 9547 | 9560 | pub const UL = darwin.UL; |
| 9561 | pub const VM = darwin.VM; | |
| 9548 | 9562 | pub const _NSGetExecutablePath = darwin._NSGetExecutablePath; |
| 9549 | 9563 | pub const __getdirentries64 = darwin.__getdirentries64; |
| 9550 | 9564 | pub const __ulock_wait = darwin.__ulock_wait; |
| ... | ... | @@ -9562,16 +9576,21 @@ pub const dispatch_semaphore_signal = darwin.dispatch_semaphore_signal; |
| 9562 | 9576 | pub const dispatch_semaphore_wait = darwin.dispatch_semaphore_wait; |
| 9563 | 9577 | pub const dispatch_time = darwin.dispatch_time; |
| 9564 | 9578 | pub const fcopyfile = darwin.fcopyfile; |
| 9579 | pub const kern_return_t = darwin.kern_return_t; | |
| 9565 | 9580 | pub const kevent64 = darwin.kevent64; |
| 9566 | 9581 | pub const mach_absolute_time = darwin.mach_absolute_time; |
| 9567 | 9582 | pub const mach_continuous_time = darwin.mach_continuous_time; |
| 9568 | 9583 | pub const mach_hdr = darwin.mach_hdr; |
| 9569 | 9584 | pub const mach_host_self = darwin.mach_host_self; |
| 9570 | 9585 | pub const mach_msg = darwin.mach_msg; |
| 9586 | pub const mach_msg_type_number_t = darwin.mach_msg_type_number_t; | |
| 9571 | 9587 | pub const mach_port_allocate = darwin.mach_port_allocate; |
| 9588 | pub const mach_port_array_t = darwin.mach_port_array_t; | |
| 9572 | 9589 | pub const mach_port_deallocate = darwin.mach_port_deallocate; |
| 9573 | 9590 | pub const mach_port_insert_right = darwin.mach_port_insert_right; |
| 9591 | pub const mach_port_name_t = darwin.mach_port_name_t; | |
| 9574 | 9592 | pub const mach_port_t = darwin.mach_port_t; |
| 9593 | pub const mach_task_basic_info = darwin.mach_task_basic_info; | |
| 9575 | 9594 | pub const mach_task_self = darwin.mach_task_self; |
| 9576 | 9595 | pub const mach_timebase_info = darwin.mach_timebase_info; |
| 9577 | 9596 | pub const mach_vm_protect = darwin.mach_vm_protect; |
| ... | ... | @@ -9602,10 +9621,12 @@ pub const posix_spawn_file_actions_addinherit_np = darwin.posix_spawn_file_actio |
| 9602 | 9621 | pub const posix_spawn_file_actions_addopen = darwin.posix_spawn_file_actions_addopen; |
| 9603 | 9622 | pub const posix_spawn_file_actions_destroy = darwin.posix_spawn_file_actions_destroy; |
| 9604 | 9623 | pub const posix_spawn_file_actions_init = darwin.posix_spawn_file_actions_init; |
| 9624 | pub const posix_spawn_file_actions_t = darwin.posix_spawn_file_actions_t; | |
| 9605 | 9625 | pub const posix_spawnattr_destroy = darwin.posix_spawnattr_destroy; |
| 9606 | 9626 | pub const posix_spawnattr_getflags = darwin.posix_spawnattr_getflags; |
| 9607 | 9627 | pub const posix_spawnattr_init = darwin.posix_spawnattr_init; |
| 9608 | 9628 | pub const posix_spawnattr_setflags = darwin.posix_spawnattr_setflags; |
| 9629 | pub const posix_spawnattr_t = darwin.posix_spawnattr_t; | |
| 9609 | 9630 | pub const posix_spawnp = darwin.posix_spawnp; |
| 9610 | 9631 | pub const pthread_attr_get_qos_class_np = darwin.pthread_attr_get_qos_class_np; |
| 9611 | 9632 | pub const pthread_attr_set_qos_class_np = darwin.pthread_attr_set_qos_class_np; |
| ... | ... | @@ -9616,17 +9637,31 @@ pub const sigaddset = darwin.sigaddset; |
| 9616 | 9637 | pub const task_for_pid = darwin.task_for_pid; |
| 9617 | 9638 | pub const task_get_exception_ports = darwin.task_get_exception_ports; |
| 9618 | 9639 | pub const task_info = darwin.task_info; |
| 9640 | pub const task_info_t = darwin.task_info_t; | |
| 9619 | 9641 | pub const task_resume = darwin.task_resume; |
| 9620 | 9642 | pub const task_set_exception_ports = darwin.task_set_exception_ports; |
| 9621 | 9643 | pub const task_suspend = darwin.task_suspend; |
| 9622 | 9644 | pub const task_threads = darwin.task_threads; |
| 9645 | pub const task_vm_info_data_t = darwin.task_vm_info_data_t; | |
| 9646 | pub const thread_basic_info = darwin.thread_basic_info; | |
| 9623 | 9647 | pub const thread_get_state = darwin.thread_get_state; |
| 9648 | pub const thread_identifier_info = darwin.thread_identifier_info; | |
| 9624 | 9649 | pub const thread_info = darwin.thread_info; |
| 9650 | pub const thread_info_t = darwin.thread_info_t; | |
| 9625 | 9651 | pub const thread_resume = darwin.thread_resume; |
| 9626 | 9652 | pub const thread_set_state = darwin.thread_set_state; |
| 9627 | 9653 | pub const vm_deallocate = darwin.vm_deallocate; |
| 9628 | 9654 | pub const vm_machine_attribute = darwin.vm_machine_attribute; |
| 9655 | pub const vm_machine_attribute_val_t = darwin.vm_machine_attribute_val_t; | |
| 9656 | pub const vm_offset_t = darwin.vm_offset_t; | |
| 9629 | 9657 | pub const vm_prot_t = darwin.vm_prot_t; |
| 9658 | pub const vm_region_basic_info_64 = darwin.vm_region_basic_info_64; | |
| 9659 | pub const vm_region_extended_info = darwin.vm_region_extended_info; | |
| 9660 | pub const vm_region_info_t = darwin.vm_region_info_t; | |
| 9661 | pub const vm_region_recurse_info_t = darwin.vm_region_recurse_info_t; | |
| 9662 | pub const vm_region_submap_info_64 = darwin.vm_region_submap_info_64; | |
| 9663 | pub const vm_region_submap_short_info_64 = darwin.vm_region_submap_short_info_64; | |
| 9664 | pub const vm_region_top_info = darwin.vm_region_top_info; | |
| 9630 | 9665 | |
| 9631 | 9666 | pub const _ksiginfo = netbsd._ksiginfo; |
| 9632 | 9667 | pub const _lwp_self = netbsd._lwp_self; |
lib/std/c/darwin.zig+63-711| ... | ... | @@ -355,31 +355,22 @@ pub const MACH_PORT_RIGHT = enum(mach_port_right_t) { |
| 355 | 355 | pub const MACH_MSG_TYPE = enum(mach_msg_type_name_t) { |
| 356 | 356 | /// Must hold receive right |
| 357 | 357 | MOVE_RECEIVE = 16, |
| 358 | ||
| 359 | 358 | /// Must hold send right(s) |
| 360 | 359 | MOVE_SEND = 17, |
| 361 | ||
| 362 | 360 | /// Must hold sendonce right |
| 363 | 361 | MOVE_SEND_ONCE = 18, |
| 364 | ||
| 365 | 362 | /// Must hold send right(s) |
| 366 | 363 | COPY_SEND = 19, |
| 367 | ||
| 368 | 364 | /// Must hold receive right |
| 369 | 365 | MAKE_SEND = 20, |
| 370 | ||
| 371 | 366 | /// Must hold receive right |
| 372 | 367 | MAKE_SEND_ONCE = 21, |
| 373 | ||
| 374 | 368 | /// NOT VALID |
| 375 | 369 | COPY_RECEIVE = 22, |
| 376 | ||
| 377 | 370 | /// Must hold receive right |
| 378 | 371 | DISPOSE_RECEIVE = 24, |
| 379 | ||
| 380 | 372 | /// Must hold send right(s) |
| 381 | 373 | DISPOSE_SEND = 25, |
| 382 | ||
| 383 | 374 | /// Must hold sendonce right |
| 384 | 375 | DISPOSE_SEND_ONCE = 26, |
| 385 | 376 | }; |
| ... | ... | @@ -469,38 +460,45 @@ pub const vm_behavior_t = i32; |
| 469 | 460 | pub const vm32_object_id_t = u32; |
| 470 | 461 | pub const vm_object_id_t = u64; |
| 471 | 462 | |
| 472 | pub const VM_INHERIT_SHARE: vm_inherit_t = 0; | |
| 473 | pub const VM_INHERIT_COPY: vm_inherit_t = 1; | |
| 474 | pub const VM_INHERIT_NONE: vm_inherit_t = 2; | |
| 475 | pub const VM_INHERIT_DONATE_COPY: vm_inherit_t = 3; | |
| 476 | pub const VM_INHERIT_DEFAULT = VM_INHERIT_COPY; | |
| 477 | ||
| 478 | pub const VM_BEHAVIOR_DEFAULT: vm_behavior_t = 0; | |
| 479 | pub const VM_BEHAVIOR_RANDOM: vm_behavior_t = 1; | |
| 480 | pub const VM_BEHAVIOR_SEQUENTIAL: vm_behavior_t = 2; | |
| 481 | pub const VM_BEHAVIOR_RSEQNTL: vm_behavior_t = 3; | |
| 482 | ||
| 483 | pub const VM_BEHAVIOR_WILLNEED: vm_behavior_t = 4; | |
| 484 | pub const VM_BEHAVIOR_DONTNEED: vm_behavior_t = 5; | |
| 485 | pub const VM_BEHAVIOR_FREE: vm_behavior_t = 6; | |
| 486 | pub const VM_BEHAVIOR_ZERO_WIRED_PAGES: vm_behavior_t = 7; | |
| 487 | pub const VM_BEHAVIOR_REUSABLE: vm_behavior_t = 8; | |
| 488 | pub const VM_BEHAVIOR_REUSE: vm_behavior_t = 9; | |
| 489 | pub const VM_BEHAVIOR_CAN_REUSE: vm_behavior_t = 10; | |
| 490 | pub const VM_BEHAVIOR_PAGEOUT: vm_behavior_t = 11; | |
| 491 | ||
| 492 | pub const VM_REGION_BASIC_INFO_64 = 9; | |
| 493 | pub const VM_REGION_EXTENDED_INFO = 13; | |
| 494 | pub const VM_REGION_TOP_INFO = 12; | |
| 495 | pub const VM_REGION_SUBMAP_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_info_64) / @sizeOf(natural_t); | |
| 496 | pub const VM_REGION_SUBMAP_SHORT_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_short_info_64) / @sizeOf(natural_t); | |
| 497 | pub const VM_REGION_BASIC_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_basic_info_64) / @sizeOf(c_int); | |
| 498 | pub const VM_REGION_EXTENDED_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_extended_info) / @sizeOf(natural_t); | |
| 499 | pub const VM_REGION_TOP_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_top_info) / @sizeOf(natural_t); | |
| 500 | ||
| 501 | pub fn VM_MAKE_TAG(tag: u8) u32 { | |
| 502 | return @as(u32, tag) << 24; | |
| 503 | } | |
| 463 | pub const VM = struct { | |
| 464 | pub const INHERIT = struct { | |
| 465 | pub const SHARE: vm_inherit_t = 0; | |
| 466 | pub const COPY: vm_inherit_t = 1; | |
| 467 | pub const NONE: vm_inherit_t = 2; | |
| 468 | pub const DONATE_COPY: vm_inherit_t = 3; | |
| 469 | pub const DEFAULT = COPY; | |
| 470 | }; | |
| 471 | ||
| 472 | pub const BEHAVIOR = struct { | |
| 473 | pub const DEFAULT: vm_behavior_t = 0; | |
| 474 | pub const RANDOM: vm_behavior_t = 1; | |
| 475 | pub const SEQUENTIAL: vm_behavior_t = 2; | |
| 476 | pub const RSEQNTL: vm_behavior_t = 3; | |
| 477 | pub const WILLNEED: vm_behavior_t = 4; | |
| 478 | pub const DONTNEED: vm_behavior_t = 5; | |
| 479 | pub const FREE: vm_behavior_t = 6; | |
| 480 | pub const ZERO_WIRED_PAGES: vm_behavior_t = 7; | |
| 481 | pub const REUSABLE: vm_behavior_t = 8; | |
| 482 | pub const REUSE: vm_behavior_t = 9; | |
| 483 | pub const CAN_REUSE: vm_behavior_t = 10; | |
| 484 | pub const PAGEOUT: vm_behavior_t = 11; | |
| 485 | }; | |
| 486 | ||
| 487 | pub const REGION = struct { | |
| 488 | pub const BASIC_INFO_64 = 9; | |
| 489 | pub const EXTENDED_INFO = 13; | |
| 490 | pub const TOP_INFO = 12; | |
| 491 | pub const SUBMAP_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_info_64) / @sizeOf(natural_t); | |
| 492 | pub const SUBMAP_SHORT_INFO_COUNT_64: mach_msg_type_number_t = @sizeOf(vm_region_submap_short_info_64) / @sizeOf(natural_t); | |
| 493 | pub const BASIC_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_basic_info_64) / @sizeOf(c_int); | |
| 494 | pub const EXTENDED_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_extended_info) / @sizeOf(natural_t); | |
| 495 | pub const TOP_INFO_COUNT: mach_msg_type_number_t = @sizeOf(vm_region_top_info) / @sizeOf(natural_t); | |
| 496 | }; | |
| 497 | ||
| 498 | pub fn MAKE_TAG(tag: u8) u32 { | |
| 499 | return @as(u32, tag) << 24; | |
| 500 | } | |
| 501 | }; | |
| 504 | 502 | |
| 505 | 503 | pub const vm_region_basic_info_64 = extern struct { |
| 506 | 504 | protection: vm_prot_t, |
| ... | ... | @@ -678,29 +676,30 @@ pub const thread_identifier_info = extern struct { |
| 678 | 676 | dispatch_qaddr: u64, |
| 679 | 677 | }; |
| 680 | 678 | |
| 681 | /// Cachability | |
| 682 | pub const MATTR_CACHE = 1; | |
| 683 | /// Migrability | |
| 684 | pub const MATTR_MIGRATE = 2; | |
| 685 | /// Replicability | |
| 686 | pub const MATTR_REPLICATE = 4; | |
| 687 | ||
| 688 | /// (Generic) turn attribute off | |
| 689 | pub const MATTR_VAL_OFF = 0; | |
| 690 | /// (Generic) turn attribute on | |
| 691 | pub const MATTR_VAL_ON = 1; | |
| 692 | /// (Generic) return current value | |
| 693 | pub const MATTR_VAL_GET = 2; | |
| 694 | /// Flush from all caches | |
| 695 | pub const MATTR_VAL_CACHE_FLUSH = 6; | |
| 696 | /// Flush from data caches | |
| 697 | pub const MATTR_VAL_DCACHE_FLUSH = 7; | |
| 698 | /// Flush from instruction caches | |
| 699 | pub const MATTR_VAL_ICACHE_FLUSH = 8; | |
| 700 | /// Sync I+D caches | |
| 701 | pub const MATTR_VAL_CACHE_SYNC = 9; | |
| 702 | /// Get page info (stats) | |
| 703 | pub const MATTR_VAL_GET_INFO = 10; | |
| 679 | pub const MATTR = struct { | |
| 680 | /// Cachability | |
| 681 | pub const CACHE = 1; | |
| 682 | /// Migrability | |
| 683 | pub const MIGRATE = 2; | |
| 684 | /// Replicability | |
| 685 | pub const REPLICATE = 4; | |
| 686 | /// (Generic) turn attribute off | |
| 687 | pub const VAL_OFF = 0; | |
| 688 | /// (Generic) turn attribute on | |
| 689 | pub const VAL_ON = 1; | |
| 690 | /// (Generic) return current value | |
| 691 | pub const VAL_GET = 2; | |
| 692 | /// Flush from all caches | |
| 693 | pub const VAL_CACHE_FLUSH = 6; | |
| 694 | /// Flush from data caches | |
| 695 | pub const VAL_DCACHE_FLUSH = 7; | |
| 696 | /// Flush from instruction caches | |
| 697 | pub const VAL_ICACHE_FLUSH = 8; | |
| 698 | /// Sync I+D caches | |
| 699 | pub const VAL_CACHE_SYNC = 9; | |
| 700 | /// Get page info (stats) | |
| 701 | pub const VAL_GET_INFO = 10; | |
| 702 | }; | |
| 704 | 703 | |
| 705 | 704 | pub const TASK_VM_INFO = 22; |
| 706 | 705 | pub const TASK_VM_INFO_COUNT: mach_msg_type_number_t = @sizeOf(task_vm_info_data_t) / @sizeOf(natural_t); |
| ... | ... | @@ -804,19 +803,14 @@ pub extern "c" fn task_info( |
| 804 | 803 | pub const mach_task_basic_info = extern struct { |
| 805 | 804 | /// Virtual memory size (bytes) |
| 806 | 805 | virtual_size: mach_vm_size_t, |
| 807 | ||
| 808 | 806 | /// Resident memory size (bytes) |
| 809 | 807 | resident_size: mach_vm_size_t, |
| 810 | ||
| 811 | 808 | /// Total user run time for terminated threads |
| 812 | 809 | user_time: time_value_t, |
| 813 | ||
| 814 | 810 | /// Total system run time for terminated threads |
| 815 | 811 | system_time: time_value_t, |
| 816 | ||
| 817 | 812 | /// Default policy for new threads |
| 818 | 813 | policy: policy_t, |
| 819 | ||
| 820 | 814 | /// Suspend count for task |
| 821 | 815 | suspend_count: mach_vm_size_t, |
| 822 | 816 | }; |
| ... | ... | @@ -925,486 +919,6 @@ pub extern "c" fn os_unfair_lock_trylock(o: os_unfair_lock_t) bool; |
| 925 | 919 | pub extern "c" fn os_unfair_lock_assert_owner(o: os_unfair_lock_t) void; |
| 926 | 920 | pub extern "c" fn os_unfair_lock_assert_not_owner(o: os_unfair_lock_t) void; |
| 927 | 921 | |
| 928 | pub fn getKernError(err: kern_return_t) KernE { | |
| 929 | return @as(KernE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err)))))); | |
| 930 | } | |
| 931 | ||
| 932 | pub fn unexpectedKernError(err: KernE) std.posix.UnexpectedError { | |
| 933 | if (std.posix.unexpected_error_tracing) { | |
| 934 | std.debug.print("unexpected error: {d}\n", .{@intFromEnum(err)}); | |
| 935 | std.debug.dumpCurrentStackTrace(null); | |
| 936 | } | |
| 937 | return error.Unexpected; | |
| 938 | } | |
| 939 | ||
| 940 | pub const MachError = error{ | |
| 941 | /// Not enough permissions held to perform the requested kernel | |
| 942 | /// call. | |
| 943 | PermissionDenied, | |
| 944 | } || std.posix.UnexpectedError; | |
| 945 | ||
| 946 | pub const MachTask = extern struct { | |
| 947 | port: mach_port_name_t, | |
| 948 | ||
| 949 | pub fn isValid(self: MachTask) bool { | |
| 950 | return self.port != TASK_NULL; | |
| 951 | } | |
| 952 | ||
| 953 | pub fn pidForTask(self: MachTask) MachError!std.c.pid_t { | |
| 954 | var pid: std.c.pid_t = undefined; | |
| 955 | switch (getKernError(pid_for_task(self.port, &pid))) { | |
| 956 | .SUCCESS => return pid, | |
| 957 | .FAILURE => return error.PermissionDenied, | |
| 958 | else => |err| return unexpectedKernError(err), | |
| 959 | } | |
| 960 | } | |
| 961 | ||
| 962 | pub fn allocatePort(self: MachTask, right: MACH_PORT_RIGHT) MachError!MachTask { | |
| 963 | var out_port: mach_port_name_t = undefined; | |
| 964 | switch (getKernError(mach_port_allocate( | |
| 965 | self.port, | |
| 966 | @intFromEnum(right), | |
| 967 | &out_port, | |
| 968 | ))) { | |
| 969 | .SUCCESS => return .{ .port = out_port }, | |
| 970 | .FAILURE => return error.PermissionDenied, | |
| 971 | else => |err| return unexpectedKernError(err), | |
| 972 | } | |
| 973 | } | |
| 974 | ||
| 975 | pub fn deallocatePort(self: MachTask, port: MachTask) void { | |
| 976 | _ = getKernError(mach_port_deallocate(self.port, port.port)); | |
| 977 | } | |
| 978 | ||
| 979 | pub fn insertRight(self: MachTask, port: MachTask, msg: MACH_MSG_TYPE) !void { | |
| 980 | switch (getKernError(mach_port_insert_right( | |
| 981 | self.port, | |
| 982 | port.port, | |
| 983 | port.port, | |
| 984 | @intFromEnum(msg), | |
| 985 | ))) { | |
| 986 | .SUCCESS => return, | |
| 987 | .FAILURE => return error.PermissionDenied, | |
| 988 | else => |err| return unexpectedKernError(err), | |
| 989 | } | |
| 990 | } | |
| 991 | ||
| 992 | pub const PortInfo = struct { | |
| 993 | mask: exception_mask_t, | |
| 994 | masks: [EXC.TYPES_COUNT]exception_mask_t, | |
| 995 | ports: [EXC.TYPES_COUNT]mach_port_t, | |
| 996 | behaviors: [EXC.TYPES_COUNT]exception_behavior_t, | |
| 997 | flavors: [EXC.TYPES_COUNT]thread_state_flavor_t, | |
| 998 | count: mach_msg_type_number_t, | |
| 999 | }; | |
| 1000 | ||
| 1001 | pub fn getExceptionPorts(self: MachTask, mask: exception_mask_t) !PortInfo { | |
| 1002 | var info = PortInfo{ | |
| 1003 | .mask = mask, | |
| 1004 | .masks = undefined, | |
| 1005 | .ports = undefined, | |
| 1006 | .behaviors = undefined, | |
| 1007 | .flavors = undefined, | |
| 1008 | .count = 0, | |
| 1009 | }; | |
| 1010 | info.count = info.ports.len / @sizeOf(mach_port_t); | |
| 1011 | ||
| 1012 | switch (getKernError(task_get_exception_ports( | |
| 1013 | self.port, | |
| 1014 | info.mask, | |
| 1015 | &info.masks, | |
| 1016 | &info.count, | |
| 1017 | &info.ports, | |
| 1018 | &info.behaviors, | |
| 1019 | &info.flavors, | |
| 1020 | ))) { | |
| 1021 | .SUCCESS => return info, | |
| 1022 | .FAILURE => return error.PermissionDenied, | |
| 1023 | else => |err| return unexpectedKernError(err), | |
| 1024 | } | |
| 1025 | } | |
| 1026 | ||
| 1027 | pub fn setExceptionPorts( | |
| 1028 | self: MachTask, | |
| 1029 | mask: exception_mask_t, | |
| 1030 | new_port: MachTask, | |
| 1031 | behavior: exception_behavior_t, | |
| 1032 | new_flavor: thread_state_flavor_t, | |
| 1033 | ) !void { | |
| 1034 | switch (getKernError(task_set_exception_ports( | |
| 1035 | self.port, | |
| 1036 | mask, | |
| 1037 | new_port.port, | |
| 1038 | behavior, | |
| 1039 | new_flavor, | |
| 1040 | ))) { | |
| 1041 | .SUCCESS => return, | |
| 1042 | .FAILURE => return error.PermissionDenied, | |
| 1043 | else => |err| return unexpectedKernError(err), | |
| 1044 | } | |
| 1045 | } | |
| 1046 | ||
| 1047 | pub const RegionInfo = struct { | |
| 1048 | pub const Tag = enum { | |
| 1049 | basic, | |
| 1050 | extended, | |
| 1051 | top, | |
| 1052 | }; | |
| 1053 | ||
| 1054 | base_addr: u64, | |
| 1055 | tag: Tag, | |
| 1056 | info: union { | |
| 1057 | basic: vm_region_basic_info_64, | |
| 1058 | extended: vm_region_extended_info, | |
| 1059 | top: vm_region_top_info, | |
| 1060 | }, | |
| 1061 | }; | |
| 1062 | ||
| 1063 | pub fn getRegionInfo( | |
| 1064 | task: MachTask, | |
| 1065 | address: u64, | |
| 1066 | len: usize, | |
| 1067 | tag: RegionInfo.Tag, | |
| 1068 | ) MachError!RegionInfo { | |
| 1069 | var info: RegionInfo = .{ | |
| 1070 | .base_addr = address, | |
| 1071 | .tag = tag, | |
| 1072 | .info = undefined, | |
| 1073 | }; | |
| 1074 | switch (tag) { | |
| 1075 | .basic => info.info = .{ .basic = undefined }, | |
| 1076 | .extended => info.info = .{ .extended = undefined }, | |
| 1077 | .top => info.info = .{ .top = undefined }, | |
| 1078 | } | |
| 1079 | var base_len: mach_vm_size_t = if (len == 1) 2 else len; | |
| 1080 | var objname: mach_port_t = undefined; | |
| 1081 | var count: mach_msg_type_number_t = switch (tag) { | |
| 1082 | .basic => VM_REGION_BASIC_INFO_COUNT, | |
| 1083 | .extended => VM_REGION_EXTENDED_INFO_COUNT, | |
| 1084 | .top => VM_REGION_TOP_INFO_COUNT, | |
| 1085 | }; | |
| 1086 | switch (getKernError(mach_vm_region( | |
| 1087 | task.port, | |
| 1088 | &info.base_addr, | |
| 1089 | &base_len, | |
| 1090 | switch (tag) { | |
| 1091 | .basic => VM_REGION_BASIC_INFO_64, | |
| 1092 | .extended => VM_REGION_EXTENDED_INFO, | |
| 1093 | .top => VM_REGION_TOP_INFO, | |
| 1094 | }, | |
| 1095 | switch (tag) { | |
| 1096 | .basic => @as(vm_region_info_t, @ptrCast(&info.info.basic)), | |
| 1097 | .extended => @as(vm_region_info_t, @ptrCast(&info.info.extended)), | |
| 1098 | .top => @as(vm_region_info_t, @ptrCast(&info.info.top)), | |
| 1099 | }, | |
| 1100 | &count, | |
| 1101 | &objname, | |
| 1102 | ))) { | |
| 1103 | .SUCCESS => return info, | |
| 1104 | .FAILURE => return error.PermissionDenied, | |
| 1105 | else => |err| return unexpectedKernError(err), | |
| 1106 | } | |
| 1107 | } | |
| 1108 | ||
| 1109 | pub const RegionSubmapInfo = struct { | |
| 1110 | pub const Tag = enum { | |
| 1111 | short, | |
| 1112 | full, | |
| 1113 | }; | |
| 1114 | ||
| 1115 | tag: Tag, | |
| 1116 | base_addr: u64, | |
| 1117 | info: union { | |
| 1118 | short: vm_region_submap_short_info_64, | |
| 1119 | full: vm_region_submap_info_64, | |
| 1120 | }, | |
| 1121 | }; | |
| 1122 | ||
| 1123 | pub fn getRegionSubmapInfo( | |
| 1124 | task: MachTask, | |
| 1125 | address: u64, | |
| 1126 | len: usize, | |
| 1127 | nesting_depth: u32, | |
| 1128 | tag: RegionSubmapInfo.Tag, | |
| 1129 | ) MachError!RegionSubmapInfo { | |
| 1130 | var info: RegionSubmapInfo = .{ | |
| 1131 | .base_addr = address, | |
| 1132 | .tag = tag, | |
| 1133 | .info = undefined, | |
| 1134 | }; | |
| 1135 | switch (tag) { | |
| 1136 | .short => info.info = .{ .short = undefined }, | |
| 1137 | .full => info.info = .{ .full = undefined }, | |
| 1138 | } | |
| 1139 | var nesting = nesting_depth; | |
| 1140 | var base_len: mach_vm_size_t = if (len == 1) 2 else len; | |
| 1141 | var count: mach_msg_type_number_t = switch (tag) { | |
| 1142 | .short => VM_REGION_SUBMAP_SHORT_INFO_COUNT_64, | |
| 1143 | .full => VM_REGION_SUBMAP_INFO_COUNT_64, | |
| 1144 | }; | |
| 1145 | switch (getKernError(mach_vm_region_recurse( | |
| 1146 | task.port, | |
| 1147 | &info.base_addr, | |
| 1148 | &base_len, | |
| 1149 | &nesting, | |
| 1150 | switch (tag) { | |
| 1151 | .short => @as(vm_region_recurse_info_t, @ptrCast(&info.info.short)), | |
| 1152 | .full => @as(vm_region_recurse_info_t, @ptrCast(&info.info.full)), | |
| 1153 | }, | |
| 1154 | &count, | |
| 1155 | ))) { | |
| 1156 | .SUCCESS => return info, | |
| 1157 | .FAILURE => return error.PermissionDenied, | |
| 1158 | else => |err| return unexpectedKernError(err), | |
| 1159 | } | |
| 1160 | } | |
| 1161 | ||
| 1162 | pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!vm_prot_t { | |
| 1163 | const info = try task.getRegionSubmapInfo(address, len, 0, .short); | |
| 1164 | return info.info.short.protection; | |
| 1165 | } | |
| 1166 | ||
| 1167 | pub fn setMaxProtection(task: MachTask, address: u64, len: usize, prot: vm_prot_t) MachError!void { | |
| 1168 | return task.setProtectionImpl(address, len, true, prot); | |
| 1169 | } | |
| 1170 | ||
| 1171 | pub fn setCurrProtection(task: MachTask, address: u64, len: usize, prot: vm_prot_t) MachError!void { | |
| 1172 | return task.setProtectionImpl(address, len, false, prot); | |
| 1173 | } | |
| 1174 | ||
| 1175 | fn setProtectionImpl(task: MachTask, address: u64, len: usize, set_max: bool, prot: vm_prot_t) MachError!void { | |
| 1176 | switch (getKernError(mach_vm_protect(task.port, address, len, @intFromBool(set_max), prot))) { | |
| 1177 | .SUCCESS => return, | |
| 1178 | .FAILURE => return error.PermissionDenied, | |
| 1179 | else => |err| return unexpectedKernError(err), | |
| 1180 | } | |
| 1181 | } | |
| 1182 | ||
| 1183 | /// Will write to VM even if current protection attributes specifically prohibit | |
| 1184 | /// us from doing so, by temporarily setting protection level to a level with VM_PROT_COPY | |
| 1185 | /// variant, and resetting after a successful or unsuccessful write. | |
| 1186 | pub fn writeMemProtected(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 1187 | const curr_prot = try task.getCurrProtection(address, buf.len); | |
| 1188 | try task.setCurrProtection( | |
| 1189 | address, | |
| 1190 | buf.len, | |
| 1191 | PROT.READ | PROT.WRITE | PROT.COPY, | |
| 1192 | ); | |
| 1193 | defer { | |
| 1194 | task.setCurrProtection(address, buf.len, curr_prot) catch {}; | |
| 1195 | } | |
| 1196 | return task.writeMem(address, buf, arch); | |
| 1197 | } | |
| 1198 | ||
| 1199 | pub fn writeMem(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 1200 | const count = buf.len; | |
| 1201 | var total_written: usize = 0; | |
| 1202 | var curr_addr = address; | |
| 1203 | const page_size = try getPageSize(task); // TODO we probably can assume value here | |
| 1204 | var out_buf = buf[0..]; | |
| 1205 | ||
| 1206 | while (total_written < count) { | |
| 1207 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_written); | |
| 1208 | switch (getKernError(mach_vm_write( | |
| 1209 | task.port, | |
| 1210 | curr_addr, | |
| 1211 | @intFromPtr(out_buf.ptr), | |
| 1212 | @as(mach_msg_type_number_t, @intCast(curr_size)), | |
| 1213 | ))) { | |
| 1214 | .SUCCESS => {}, | |
| 1215 | .FAILURE => return error.PermissionDenied, | |
| 1216 | else => |err| return unexpectedKernError(err), | |
| 1217 | } | |
| 1218 | ||
| 1219 | switch (arch) { | |
| 1220 | .aarch64 => { | |
| 1221 | var mattr_value: vm_machine_attribute_val_t = MATTR_VAL_CACHE_FLUSH; | |
| 1222 | switch (getKernError(vm_machine_attribute( | |
| 1223 | task.port, | |
| 1224 | curr_addr, | |
| 1225 | curr_size, | |
| 1226 | MATTR_CACHE, | |
| 1227 | &mattr_value, | |
| 1228 | ))) { | |
| 1229 | .SUCCESS => {}, | |
| 1230 | .FAILURE => return error.PermissionDenied, | |
| 1231 | else => |err| return unexpectedKernError(err), | |
| 1232 | } | |
| 1233 | }, | |
| 1234 | .x86_64 => {}, | |
| 1235 | else => unreachable, | |
| 1236 | } | |
| 1237 | ||
| 1238 | out_buf = out_buf[curr_size..]; | |
| 1239 | total_written += curr_size; | |
| 1240 | curr_addr += curr_size; | |
| 1241 | } | |
| 1242 | ||
| 1243 | return total_written; | |
| 1244 | } | |
| 1245 | ||
| 1246 | pub fn readMem(task: MachTask, address: u64, buf: []u8) MachError!usize { | |
| 1247 | const count = buf.len; | |
| 1248 | var total_read: usize = 0; | |
| 1249 | var curr_addr = address; | |
| 1250 | const page_size = try getPageSize(task); // TODO we probably can assume value here | |
| 1251 | var out_buf = buf[0..]; | |
| 1252 | ||
| 1253 | while (total_read < count) { | |
| 1254 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_read); | |
| 1255 | var curr_bytes_read: mach_msg_type_number_t = 0; | |
| 1256 | var vm_memory: vm_offset_t = undefined; | |
| 1257 | switch (getKernError(mach_vm_read(task.port, curr_addr, curr_size, &vm_memory, &curr_bytes_read))) { | |
| 1258 | .SUCCESS => {}, | |
| 1259 | .FAILURE => return error.PermissionDenied, | |
| 1260 | else => |err| return unexpectedKernError(err), | |
| 1261 | } | |
| 1262 | ||
| 1263 | @memcpy(out_buf[0..curr_bytes_read], @as([*]const u8, @ptrFromInt(vm_memory))); | |
| 1264 | _ = vm_deallocate(mach_task_self(), vm_memory, curr_bytes_read); | |
| 1265 | ||
| 1266 | out_buf = out_buf[curr_bytes_read..]; | |
| 1267 | curr_addr += curr_bytes_read; | |
| 1268 | total_read += curr_bytes_read; | |
| 1269 | } | |
| 1270 | ||
| 1271 | return total_read; | |
| 1272 | } | |
| 1273 | ||
| 1274 | fn maxBytesLeftInPage(page_size: usize, address: u64, count: usize) usize { | |
| 1275 | var left = count; | |
| 1276 | if (page_size > 0) { | |
| 1277 | const page_offset = address % page_size; | |
| 1278 | const bytes_left_in_page = page_size - page_offset; | |
| 1279 | if (count > bytes_left_in_page) { | |
| 1280 | left = bytes_left_in_page; | |
| 1281 | } | |
| 1282 | } | |
| 1283 | return left; | |
| 1284 | } | |
| 1285 | ||
| 1286 | fn getPageSize(task: MachTask) MachError!usize { | |
| 1287 | if (task.isValid()) { | |
| 1288 | var info_count = TASK_VM_INFO_COUNT; | |
| 1289 | var vm_info: task_vm_info_data_t = undefined; | |
| 1290 | switch (getKernError(task_info( | |
| 1291 | task.port, | |
| 1292 | TASK_VM_INFO, | |
| 1293 | @as(task_info_t, @ptrCast(&vm_info)), | |
| 1294 | &info_count, | |
| 1295 | ))) { | |
| 1296 | .SUCCESS => return @as(usize, @intCast(vm_info.page_size)), | |
| 1297 | else => {}, | |
| 1298 | } | |
| 1299 | } | |
| 1300 | var page_size: vm_size_t = undefined; | |
| 1301 | switch (getKernError(_host_page_size(mach_host_self(), &page_size))) { | |
| 1302 | .SUCCESS => return page_size, | |
| 1303 | else => |err| return unexpectedKernError(err), | |
| 1304 | } | |
| 1305 | } | |
| 1306 | ||
| 1307 | pub fn basicTaskInfo(task: MachTask) MachError!mach_task_basic_info { | |
| 1308 | var info: mach_task_basic_info = undefined; | |
| 1309 | var count = MACH_TASK_BASIC_INFO_COUNT; | |
| 1310 | switch (getKernError(task_info( | |
| 1311 | task.port, | |
| 1312 | MACH_TASK_BASIC_INFO, | |
| 1313 | @as(task_info_t, @ptrCast(&info)), | |
| 1314 | &count, | |
| 1315 | ))) { | |
| 1316 | .SUCCESS => return info, | |
| 1317 | else => |err| return unexpectedKernError(err), | |
| 1318 | } | |
| 1319 | } | |
| 1320 | ||
| 1321 | pub fn @"resume"(task: MachTask) MachError!void { | |
| 1322 | switch (getKernError(task_resume(task.port))) { | |
| 1323 | .SUCCESS => {}, | |
| 1324 | else => |err| return unexpectedKernError(err), | |
| 1325 | } | |
| 1326 | } | |
| 1327 | ||
| 1328 | pub fn @"suspend"(task: MachTask) MachError!void { | |
| 1329 | switch (getKernError(task_suspend(task.port))) { | |
| 1330 | .SUCCESS => {}, | |
| 1331 | else => |err| return unexpectedKernError(err), | |
| 1332 | } | |
| 1333 | } | |
| 1334 | ||
| 1335 | const ThreadList = struct { | |
| 1336 | buf: []MachThread, | |
| 1337 | ||
| 1338 | pub fn deinit(list: ThreadList) void { | |
| 1339 | const self_task = machTaskForSelf(); | |
| 1340 | _ = vm_deallocate( | |
| 1341 | self_task.port, | |
| 1342 | @intFromPtr(list.buf.ptr), | |
| 1343 | @as(vm_size_t, @intCast(list.buf.len * @sizeOf(mach_port_t))), | |
| 1344 | ); | |
| 1345 | } | |
| 1346 | }; | |
| 1347 | ||
| 1348 | pub fn getThreads(task: MachTask) MachError!ThreadList { | |
| 1349 | var thread_list: mach_port_array_t = undefined; | |
| 1350 | var thread_count: mach_msg_type_number_t = undefined; | |
| 1351 | switch (getKernError(task_threads(task.port, &thread_list, &thread_count))) { | |
| 1352 | .SUCCESS => return ThreadList{ .buf = @as([*]MachThread, @ptrCast(thread_list))[0..thread_count] }, | |
| 1353 | else => |err| return unexpectedKernError(err), | |
| 1354 | } | |
| 1355 | } | |
| 1356 | }; | |
| 1357 | ||
| 1358 | pub const MachThread = extern struct { | |
| 1359 | port: mach_port_t, | |
| 1360 | ||
| 1361 | pub fn isValid(thread: MachThread) bool { | |
| 1362 | return thread.port != THREAD_NULL; | |
| 1363 | } | |
| 1364 | ||
| 1365 | pub fn getBasicInfo(thread: MachThread) MachError!thread_basic_info { | |
| 1366 | var info: thread_basic_info = undefined; | |
| 1367 | var count = THREAD_BASIC_INFO_COUNT; | |
| 1368 | switch (getKernError(thread_info( | |
| 1369 | thread.port, | |
| 1370 | THREAD_BASIC_INFO, | |
| 1371 | @as(thread_info_t, @ptrCast(&info)), | |
| 1372 | &count, | |
| 1373 | ))) { | |
| 1374 | .SUCCESS => return info, | |
| 1375 | else => |err| return unexpectedKernError(err), | |
| 1376 | } | |
| 1377 | } | |
| 1378 | ||
| 1379 | pub fn getIdentifierInfo(thread: MachThread) MachError!thread_identifier_info { | |
| 1380 | var info: thread_identifier_info = undefined; | |
| 1381 | var count = THREAD_IDENTIFIER_INFO_COUNT; | |
| 1382 | switch (getKernError(thread_info( | |
| 1383 | thread.port, | |
| 1384 | THREAD_IDENTIFIER_INFO, | |
| 1385 | @as(thread_info_t, @ptrCast(&info)), | |
| 1386 | &count, | |
| 1387 | ))) { | |
| 1388 | .SUCCESS => return info, | |
| 1389 | else => |err| return unexpectedKernError(err), | |
| 1390 | } | |
| 1391 | } | |
| 1392 | }; | |
| 1393 | ||
| 1394 | pub fn machTaskForPid(pid: std.c.pid_t) MachError!MachTask { | |
| 1395 | var port: mach_port_name_t = undefined; | |
| 1396 | switch (getKernError(task_for_pid(mach_task_self(), pid, &port))) { | |
| 1397 | .SUCCESS => {}, | |
| 1398 | .FAILURE => return error.PermissionDenied, | |
| 1399 | else => |err| return unexpectedKernError(err), | |
| 1400 | } | |
| 1401 | return MachTask{ .port = port }; | |
| 1402 | } | |
| 1403 | ||
| 1404 | pub fn machTaskForSelf() MachTask { | |
| 1405 | return .{ .port = mach_task_self() }; | |
| 1406 | } | |
| 1407 | ||
| 1408 | 922 | pub const os_signpost_id_t = u64; |
| 1409 | 923 | |
| 1410 | 924 | pub const OS_SIGNPOST_ID_NULL: os_signpost_id_t = 0; |
| ... | ... | @@ -1503,168 +1017,6 @@ pub const KEVENT_FLAG_ERROR_EVENTS = 0x002; |
| 1503 | 1017 | |
| 1504 | 1018 | pub const SYSPROTO_EVENT = 1; |
| 1505 | 1019 | pub const SYSPROTO_CONTROL = 2; |
| 1506 | /// Kernel return values | |
| 1507 | pub const KernE = enum(u32) { | |
| 1508 | SUCCESS = 0, | |
| 1509 | /// Specified address is not currently valid | |
| 1510 | INVALID_ADDRESS = 1, | |
| 1511 | /// Specified memory is valid, but does not permit the | |
| 1512 | /// required forms of access. | |
| 1513 | PROTECTION_FAILURE = 2, | |
| 1514 | /// The address range specified is already in use, or | |
| 1515 | /// no address range of the size specified could be | |
| 1516 | /// found. | |
| 1517 | NO_SPACE = 3, | |
| 1518 | /// The function requested was not applicable to this | |
| 1519 | /// type of argument, or an argument is invalid | |
| 1520 | INVALID_ARGUMENT = 4, | |
| 1521 | /// The function could not be performed. A catch-all. | |
| 1522 | FAILURE = 5, | |
| 1523 | /// A system resource could not be allocated to fulfill | |
| 1524 | /// this request. This failure may not be permanent. | |
| 1525 | RESOURCE_SHORTAGE = 6, | |
| 1526 | /// The task in question does not hold receive rights | |
| 1527 | /// for the port argument. | |
| 1528 | NOT_RECEIVER = 7, | |
| 1529 | /// Bogus access restriction. | |
| 1530 | NO_ACCESS = 8, | |
| 1531 | /// During a page fault, the target address refers to a | |
| 1532 | /// memory object that has been destroyed. This | |
| 1533 | /// failure is permanent. | |
| 1534 | MEMORY_FAILURE = 9, | |
| 1535 | /// During a page fault, the memory object indicated | |
| 1536 | /// that the data could not be returned. This failure | |
| 1537 | /// may be temporary; future attempts to access this | |
| 1538 | /// same data may succeed, as defined by the memory | |
| 1539 | /// object. | |
| 1540 | MEMORY_ERROR = 10, | |
| 1541 | /// The receive right is already a member of the portset. | |
| 1542 | ALREADY_IN_SET = 11, | |
| 1543 | /// The receive right is not a member of a port set. | |
| 1544 | NOT_IN_SET = 12, | |
| 1545 | /// The name already denotes a right in the task. | |
| 1546 | NAME_EXISTS = 13, | |
| 1547 | /// The operation was aborted. Ipc code will | |
| 1548 | /// catch this and reflect it as a message error. | |
| 1549 | ABORTED = 14, | |
| 1550 | /// The name doesn't denote a right in the task. | |
| 1551 | INVALID_NAME = 15, | |
| 1552 | /// Target task isn't an active task. | |
| 1553 | INVALID_TASK = 16, | |
| 1554 | /// The name denotes a right, but not an appropriate right. | |
| 1555 | INVALID_RIGHT = 17, | |
| 1556 | /// A blatant range error. | |
| 1557 | INVALID_VALUE = 18, | |
| 1558 | /// Operation would overflow limit on user-references. | |
| 1559 | UREFS_OVERFLOW = 19, | |
| 1560 | /// The supplied (port) capability is improper. | |
| 1561 | INVALID_CAPABILITY = 20, | |
| 1562 | /// The task already has send or receive rights | |
| 1563 | /// for the port under another name. | |
| 1564 | RIGHT_EXISTS = 21, | |
| 1565 | /// Target host isn't actually a host. | |
| 1566 | INVALID_HOST = 22, | |
| 1567 | /// An attempt was made to supply "precious" data | |
| 1568 | /// for memory that is already present in a | |
| 1569 | /// memory object. | |
| 1570 | MEMORY_PRESENT = 23, | |
| 1571 | /// A page was requested of a memory manager via | |
| 1572 | /// memory_object_data_request for an object using | |
| 1573 | /// a MEMORY_OBJECT_COPY_CALL strategy, with the | |
| 1574 | /// VM_PROT_WANTS_COPY flag being used to specify | |
| 1575 | /// that the page desired is for a copy of the | |
| 1576 | /// object, and the memory manager has detected | |
| 1577 | /// the page was pushed into a copy of the object | |
| 1578 | /// while the kernel was walking the shadow chain | |
| 1579 | /// from the copy to the object. This error code | |
| 1580 | /// is delivered via memory_object_data_error | |
| 1581 | /// and is handled by the kernel (it forces the | |
| 1582 | /// kernel to restart the fault). It will not be | |
| 1583 | /// seen by users. | |
| 1584 | MEMORY_DATA_MOVED = 24, | |
| 1585 | /// A strategic copy was attempted of an object | |
| 1586 | /// upon which a quicker copy is now possible. | |
| 1587 | /// The caller should retry the copy using | |
| 1588 | /// vm_object_copy_quickly. This error code | |
| 1589 | /// is seen only by the kernel. | |
| 1590 | MEMORY_RESTART_COPY = 25, | |
| 1591 | /// An argument applied to assert processor set privilege | |
| 1592 | /// was not a processor set control port. | |
| 1593 | INVALID_PROCESSOR_SET = 26, | |
| 1594 | /// The specified scheduling attributes exceed the thread's | |
| 1595 | /// limits. | |
| 1596 | POLICY_LIMIT = 27, | |
| 1597 | /// The specified scheduling policy is not currently | |
| 1598 | /// enabled for the processor set. | |
| 1599 | INVALID_POLICY = 28, | |
| 1600 | /// The external memory manager failed to initialize the | |
| 1601 | /// memory object. | |
| 1602 | INVALID_OBJECT = 29, | |
| 1603 | /// A thread is attempting to wait for an event for which | |
| 1604 | /// there is already a waiting thread. | |
| 1605 | ALREADY_WAITING = 30, | |
| 1606 | /// An attempt was made to destroy the default processor | |
| 1607 | /// set. | |
| 1608 | DEFAULT_SET = 31, | |
| 1609 | /// An attempt was made to fetch an exception port that is | |
| 1610 | /// protected, or to abort a thread while processing a | |
| 1611 | /// protected exception. | |
| 1612 | EXCEPTION_PROTECTED = 32, | |
| 1613 | /// A ledger was required but not supplied. | |
| 1614 | INVALID_LEDGER = 33, | |
| 1615 | /// The port was not a memory cache control port. | |
| 1616 | INVALID_MEMORY_CONTROL = 34, | |
| 1617 | /// An argument supplied to assert security privilege | |
| 1618 | /// was not a host security port. | |
| 1619 | INVALID_SECURITY = 35, | |
| 1620 | /// thread_depress_abort was called on a thread which | |
| 1621 | /// was not currently depressed. | |
| 1622 | NOT_DEPRESSED = 36, | |
| 1623 | /// Object has been terminated and is no longer available | |
| 1624 | TERMINATED = 37, | |
| 1625 | /// Lock set has been destroyed and is no longer available. | |
| 1626 | LOCK_SET_DESTROYED = 38, | |
| 1627 | /// The thread holding the lock terminated before releasing | |
| 1628 | /// the lock | |
| 1629 | LOCK_UNSTABLE = 39, | |
| 1630 | /// The lock is already owned by another thread | |
| 1631 | LOCK_OWNED = 40, | |
| 1632 | /// The lock is already owned by the calling thread | |
| 1633 | LOCK_OWNED_SELF = 41, | |
| 1634 | /// Semaphore has been destroyed and is no longer available. | |
| 1635 | SEMAPHORE_DESTROYED = 42, | |
| 1636 | /// Return from RPC indicating the target server was | |
| 1637 | /// terminated before it successfully replied | |
| 1638 | RPC_SERVER_TERMINATED = 43, | |
| 1639 | /// Terminate an orphaned activation. | |
| 1640 | RPC_TERMINATE_ORPHAN = 44, | |
| 1641 | /// Allow an orphaned activation to continue executing. | |
| 1642 | RPC_CONTINUE_ORPHAN = 45, | |
| 1643 | /// Empty thread activation (No thread linked to it) | |
| 1644 | NOT_SUPPORTED = 46, | |
| 1645 | /// Remote node down or inaccessible. | |
| 1646 | NODE_DOWN = 47, | |
| 1647 | /// A signalled thread was not actually waiting. | |
| 1648 | NOT_WAITING = 48, | |
| 1649 | /// Some thread-oriented operation (semaphore_wait) timed out | |
| 1650 | OPERATION_TIMED_OUT = 49, | |
| 1651 | /// During a page fault, indicates that the page was rejected | |
| 1652 | /// as a result of a signature check. | |
| 1653 | CODESIGN_ERROR = 50, | |
| 1654 | /// The requested property cannot be changed at this time. | |
| 1655 | POLICY_STATIC = 51, | |
| 1656 | /// The provided buffer is of insufficient size for the requested data. | |
| 1657 | INSUFFICIENT_BUFFER_SIZE = 52, | |
| 1658 | /// Denied by security policy | |
| 1659 | DENIED = 53, | |
| 1660 | /// The KC on which the function is operating is missing | |
| 1661 | MISSING_KC = 54, | |
| 1662 | /// The KC on which the function is operating is invalid | |
| 1663 | INVALID_KC = 55, | |
| 1664 | /// A search or query operation did not return a result | |
| 1665 | NOT_FOUND = 56, | |
| 1666 | _, | |
| 1667 | }; | |
| 1668 | 1020 | |
| 1669 | 1021 | pub const mach_msg_return_t = kern_return_t; |
| 1670 | 1022 |
src/link/MachO.zig+645-2| ... | ... | @@ -3779,7 +3779,7 @@ pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols { |
| 3779 | 3779 | pub fn ptraceAttach(self: *MachO, pid: std.posix.pid_t) !void { |
| 3780 | 3780 | if (!is_hot_update_compatible) return; |
| 3781 | 3781 | |
| 3782 | const mach_task = try std.c.machTaskForPid(pid); | |
| 3782 | const mach_task = try machTaskForPid(pid); | |
| 3783 | 3783 | log.debug("Mach task for pid {d}: {any}", .{ pid, mach_task }); |
| 3784 | 3784 | self.hot_state.mach_task = mach_task; |
| 3785 | 3785 | |
| ... | ... | @@ -4058,7 +4058,7 @@ pub const LiteralPool = struct { |
| 4058 | 4058 | }; |
| 4059 | 4059 | |
| 4060 | 4060 | const HotUpdateState = struct { |
| 4061 | mach_task: ?std.c.MachTask = null, | |
| 4061 | mach_task: ?MachTask = null, | |
| 4062 | 4062 | }; |
| 4063 | 4063 | |
| 4064 | 4064 | pub const SymtabCtx = struct { |
| ... | ... | @@ -4562,3 +4562,646 @@ const UnwindInfo = @import("MachO/UnwindInfo.zig"); |
| 4562 | 4562 | const WeakBind = bind.WeakBind; |
| 4563 | 4563 | const ZigGotSection = synthetic.ZigGotSection; |
| 4564 | 4564 | const ZigObject = @import("MachO/ZigObject.zig"); |
| 4565 | ||
| 4566 | pub const MachError = error{ | |
| 4567 | /// Not enough permissions held to perform the requested kernel | |
| 4568 | /// call. | |
| 4569 | PermissionDenied, | |
| 4570 | } || std.posix.UnexpectedError; | |
| 4571 | ||
| 4572 | pub const MachTask = extern struct { | |
| 4573 | port: std.c.mach_port_name_t, | |
| 4574 | ||
| 4575 | pub fn isValid(self: MachTask) bool { | |
| 4576 | return self.port != std.c.TASK_NULL; | |
| 4577 | } | |
| 4578 | ||
| 4579 | pub fn pidForTask(self: MachTask) MachError!std.c.pid_t { | |
| 4580 | var pid: std.c.pid_t = undefined; | |
| 4581 | switch (getKernError(std.c.pid_for_task(self.port, &pid))) { | |
| 4582 | .SUCCESS => return pid, | |
| 4583 | .FAILURE => return error.PermissionDenied, | |
| 4584 | else => |err| return unexpectedKernError(err), | |
| 4585 | } | |
| 4586 | } | |
| 4587 | ||
| 4588 | pub fn allocatePort(self: MachTask, right: std.c.MACH_PORT_RIGHT) MachError!MachTask { | |
| 4589 | var out_port: std.c.mach_port_name_t = undefined; | |
| 4590 | switch (getKernError(std.c.mach_port_allocate( | |
| 4591 | self.port, | |
| 4592 | @intFromEnum(right), | |
| 4593 | &out_port, | |
| 4594 | ))) { | |
| 4595 | .SUCCESS => return .{ .port = out_port }, | |
| 4596 | .FAILURE => return error.PermissionDenied, | |
| 4597 | else => |err| return unexpectedKernError(err), | |
| 4598 | } | |
| 4599 | } | |
| 4600 | ||
| 4601 | pub fn deallocatePort(self: MachTask, port: MachTask) void { | |
| 4602 | _ = getKernError(std.c.mach_port_deallocate(self.port, port.port)); | |
| 4603 | } | |
| 4604 | ||
| 4605 | pub fn insertRight(self: MachTask, port: MachTask, msg: std.c.MACH_MSG_TYPE) !void { | |
| 4606 | switch (getKernError(std.c.mach_port_insert_right( | |
| 4607 | self.port, | |
| 4608 | port.port, | |
| 4609 | port.port, | |
| 4610 | @intFromEnum(msg), | |
| 4611 | ))) { | |
| 4612 | .SUCCESS => return, | |
| 4613 | .FAILURE => return error.PermissionDenied, | |
| 4614 | else => |err| return unexpectedKernError(err), | |
| 4615 | } | |
| 4616 | } | |
| 4617 | ||
| 4618 | pub const PortInfo = struct { | |
| 4619 | mask: std.c.exception_mask_t, | |
| 4620 | masks: [std.c.EXC.TYPES_COUNT]std.c.exception_mask_t, | |
| 4621 | ports: [std.c.EXC.TYPES_COUNT]std.c.mach_port_t, | |
| 4622 | behaviors: [std.c.EXC.TYPES_COUNT]std.c.exception_behavior_t, | |
| 4623 | flavors: [std.c.EXC.TYPES_COUNT]std.c.thread_state_flavor_t, | |
| 4624 | count: std.c.mach_msg_type_number_t, | |
| 4625 | }; | |
| 4626 | ||
| 4627 | pub fn getExceptionPorts(self: MachTask, mask: std.c.exception_mask_t) !PortInfo { | |
| 4628 | var info: PortInfo = .{ | |
| 4629 | .mask = mask, | |
| 4630 | .masks = undefined, | |
| 4631 | .ports = undefined, | |
| 4632 | .behaviors = undefined, | |
| 4633 | .flavors = undefined, | |
| 4634 | .count = 0, | |
| 4635 | }; | |
| 4636 | info.count = info.ports.len / @sizeOf(std.c.mach_port_t); | |
| 4637 | ||
| 4638 | switch (getKernError(std.c.task_get_exception_ports( | |
| 4639 | self.port, | |
| 4640 | info.mask, | |
| 4641 | &info.masks, | |
| 4642 | &info.count, | |
| 4643 | &info.ports, | |
| 4644 | &info.behaviors, | |
| 4645 | &info.flavors, | |
| 4646 | ))) { | |
| 4647 | .SUCCESS => return info, | |
| 4648 | .FAILURE => return error.PermissionDenied, | |
| 4649 | else => |err| return unexpectedKernError(err), | |
| 4650 | } | |
| 4651 | } | |
| 4652 | ||
| 4653 | pub fn setExceptionPorts( | |
| 4654 | self: MachTask, | |
| 4655 | mask: std.c.exception_mask_t, | |
| 4656 | new_port: MachTask, | |
| 4657 | behavior: std.c.exception_behavior_t, | |
| 4658 | new_flavor: std.c.thread_state_flavor_t, | |
| 4659 | ) !void { | |
| 4660 | switch (getKernError(std.c.task_set_exception_ports( | |
| 4661 | self.port, | |
| 4662 | mask, | |
| 4663 | new_port.port, | |
| 4664 | behavior, | |
| 4665 | new_flavor, | |
| 4666 | ))) { | |
| 4667 | .SUCCESS => return, | |
| 4668 | .FAILURE => return error.PermissionDenied, | |
| 4669 | else => |err| return unexpectedKernError(err), | |
| 4670 | } | |
| 4671 | } | |
| 4672 | ||
| 4673 | pub const RegionInfo = struct { | |
| 4674 | pub const Tag = enum { | |
| 4675 | basic, | |
| 4676 | extended, | |
| 4677 | top, | |
| 4678 | }; | |
| 4679 | ||
| 4680 | base_addr: u64, | |
| 4681 | tag: Tag, | |
| 4682 | info: union { | |
| 4683 | basic: std.c.vm_region_basic_info_64, | |
| 4684 | extended: std.c.vm_region_extended_info, | |
| 4685 | top: std.c.vm_region_top_info, | |
| 4686 | }, | |
| 4687 | }; | |
| 4688 | ||
| 4689 | pub fn getRegionInfo( | |
| 4690 | task: MachTask, | |
| 4691 | address: u64, | |
| 4692 | len: usize, | |
| 4693 | tag: RegionInfo.Tag, | |
| 4694 | ) MachError!RegionInfo { | |
| 4695 | var info: RegionInfo = .{ | |
| 4696 | .base_addr = address, | |
| 4697 | .tag = tag, | |
| 4698 | .info = undefined, | |
| 4699 | }; | |
| 4700 | switch (tag) { | |
| 4701 | .basic => info.info = .{ .basic = undefined }, | |
| 4702 | .extended => info.info = .{ .extended = undefined }, | |
| 4703 | .top => info.info = .{ .top = undefined }, | |
| 4704 | } | |
| 4705 | var base_len: std.c.mach_vm_size_t = if (len == 1) 2 else len; | |
| 4706 | var objname: std.c.mach_port_t = undefined; | |
| 4707 | var count: std.c.mach_msg_type_number_t = switch (tag) { | |
| 4708 | .basic => std.c.VM.REGION.BASIC_INFO_COUNT, | |
| 4709 | .extended => std.c.VM.REGION.EXTENDED_INFO_COUNT, | |
| 4710 | .top => std.c.VM.REGION.TOP_INFO_COUNT, | |
| 4711 | }; | |
| 4712 | switch (getKernError(std.c.mach_vm_region( | |
| 4713 | task.port, | |
| 4714 | &info.base_addr, | |
| 4715 | &base_len, | |
| 4716 | switch (tag) { | |
| 4717 | .basic => std.c.VM.REGION.BASIC_INFO_64, | |
| 4718 | .extended => std.c.VM.REGION.EXTENDED_INFO, | |
| 4719 | .top => std.c.VM.REGION.TOP_INFO, | |
| 4720 | }, | |
| 4721 | switch (tag) { | |
| 4722 | .basic => @as(std.c.vm_region_info_t, @ptrCast(&info.info.basic)), | |
| 4723 | .extended => @as(std.c.vm_region_info_t, @ptrCast(&info.info.extended)), | |
| 4724 | .top => @as(std.c.vm_region_info_t, @ptrCast(&info.info.top)), | |
| 4725 | }, | |
| 4726 | &count, | |
| 4727 | &objname, | |
| 4728 | ))) { | |
| 4729 | .SUCCESS => return info, | |
| 4730 | .FAILURE => return error.PermissionDenied, | |
| 4731 | else => |err| return unexpectedKernError(err), | |
| 4732 | } | |
| 4733 | } | |
| 4734 | ||
| 4735 | pub const RegionSubmapInfo = struct { | |
| 4736 | pub const Tag = enum { | |
| 4737 | short, | |
| 4738 | full, | |
| 4739 | }; | |
| 4740 | ||
| 4741 | tag: Tag, | |
| 4742 | base_addr: u64, | |
| 4743 | info: union { | |
| 4744 | short: std.c.vm_region_submap_short_info_64, | |
| 4745 | full: std.c.vm_region_submap_info_64, | |
| 4746 | }, | |
| 4747 | }; | |
| 4748 | ||
| 4749 | pub fn getRegionSubmapInfo( | |
| 4750 | task: MachTask, | |
| 4751 | address: u64, | |
| 4752 | len: usize, | |
| 4753 | nesting_depth: u32, | |
| 4754 | tag: RegionSubmapInfo.Tag, | |
| 4755 | ) MachError!RegionSubmapInfo { | |
| 4756 | var info: RegionSubmapInfo = .{ | |
| 4757 | .base_addr = address, | |
| 4758 | .tag = tag, | |
| 4759 | .info = undefined, | |
| 4760 | }; | |
| 4761 | switch (tag) { | |
| 4762 | .short => info.info = .{ .short = undefined }, | |
| 4763 | .full => info.info = .{ .full = undefined }, | |
| 4764 | } | |
| 4765 | var nesting = nesting_depth; | |
| 4766 | var base_len: std.c.mach_vm_size_t = if (len == 1) 2 else len; | |
| 4767 | var count: std.c.mach_msg_type_number_t = switch (tag) { | |
| 4768 | .short => std.c.VM.REGION.SUBMAP_SHORT_INFO_COUNT_64, | |
| 4769 | .full => std.c.VM.REGION.SUBMAP_INFO_COUNT_64, | |
| 4770 | }; | |
| 4771 | switch (getKernError(std.c.mach_vm_region_recurse( | |
| 4772 | task.port, | |
| 4773 | &info.base_addr, | |
| 4774 | &base_len, | |
| 4775 | &nesting, | |
| 4776 | switch (tag) { | |
| 4777 | .short => @as(std.c.vm_region_recurse_info_t, @ptrCast(&info.info.short)), | |
| 4778 | .full => @as(std.c.vm_region_recurse_info_t, @ptrCast(&info.info.full)), | |
| 4779 | }, | |
| 4780 | &count, | |
| 4781 | ))) { | |
| 4782 | .SUCCESS => return info, | |
| 4783 | .FAILURE => return error.PermissionDenied, | |
| 4784 | else => |err| return unexpectedKernError(err), | |
| 4785 | } | |
| 4786 | } | |
| 4787 | ||
| 4788 | pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!std.c.vm_prot_t { | |
| 4789 | const info = try task.getRegionSubmapInfo(address, len, 0, .short); | |
| 4790 | return info.info.short.protection; | |
| 4791 | } | |
| 4792 | ||
| 4793 | pub fn setMaxProtection(task: MachTask, address: u64, len: usize, prot: std.c.vm_prot_t) MachError!void { | |
| 4794 | return task.setProtectionImpl(address, len, true, prot); | |
| 4795 | } | |
| 4796 | ||
| 4797 | pub fn setCurrProtection(task: MachTask, address: u64, len: usize, prot: std.c.vm_prot_t) MachError!void { | |
| 4798 | return task.setProtectionImpl(address, len, false, prot); | |
| 4799 | } | |
| 4800 | ||
| 4801 | fn setProtectionImpl(task: MachTask, address: u64, len: usize, set_max: bool, prot: std.c.vm_prot_t) MachError!void { | |
| 4802 | switch (getKernError(std.c.mach_vm_protect(task.port, address, len, @intFromBool(set_max), prot))) { | |
| 4803 | .SUCCESS => return, | |
| 4804 | .FAILURE => return error.PermissionDenied, | |
| 4805 | else => |err| return unexpectedKernError(err), | |
| 4806 | } | |
| 4807 | } | |
| 4808 | ||
| 4809 | /// Will write to VM even if current protection attributes specifically prohibit | |
| 4810 | /// us from doing so, by temporarily setting protection level to a level with VM_PROT_COPY | |
| 4811 | /// variant, and resetting after a successful or unsuccessful write. | |
| 4812 | pub fn writeMemProtected(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 4813 | const curr_prot = try task.getCurrProtection(address, buf.len); | |
| 4814 | try task.setCurrProtection( | |
| 4815 | address, | |
| 4816 | buf.len, | |
| 4817 | std.c.PROT.READ | std.c.PROT.WRITE | std.c.PROT.COPY, | |
| 4818 | ); | |
| 4819 | defer { | |
| 4820 | task.setCurrProtection(address, buf.len, curr_prot) catch {}; | |
| 4821 | } | |
| 4822 | return task.writeMem(address, buf, arch); | |
| 4823 | } | |
| 4824 | ||
| 4825 | pub fn writeMem(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 4826 | const count = buf.len; | |
| 4827 | var total_written: usize = 0; | |
| 4828 | var curr_addr = address; | |
| 4829 | const page_size = try MachTask.getPageSize(task); // TODO we probably can assume value here | |
| 4830 | var out_buf = buf[0..]; | |
| 4831 | ||
| 4832 | while (total_written < count) { | |
| 4833 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_written); | |
| 4834 | switch (getKernError(std.c.mach_vm_write( | |
| 4835 | task.port, | |
| 4836 | curr_addr, | |
| 4837 | @intFromPtr(out_buf.ptr), | |
| 4838 | @as(std.c.mach_msg_type_number_t, @intCast(curr_size)), | |
| 4839 | ))) { | |
| 4840 | .SUCCESS => {}, | |
| 4841 | .FAILURE => return error.PermissionDenied, | |
| 4842 | else => |err| return unexpectedKernError(err), | |
| 4843 | } | |
| 4844 | ||
| 4845 | switch (arch) { | |
| 4846 | .aarch64 => { | |
| 4847 | var mattr_value: std.c.vm_machine_attribute_val_t = std.c.MATTR.VAL_CACHE_FLUSH; | |
| 4848 | switch (getKernError(std.c.vm_machine_attribute( | |
| 4849 | task.port, | |
| 4850 | curr_addr, | |
| 4851 | curr_size, | |
| 4852 | std.c.MATTR.CACHE, | |
| 4853 | &mattr_value, | |
| 4854 | ))) { | |
| 4855 | .SUCCESS => {}, | |
| 4856 | .FAILURE => return error.PermissionDenied, | |
| 4857 | else => |err| return unexpectedKernError(err), | |
| 4858 | } | |
| 4859 | }, | |
| 4860 | .x86_64 => {}, | |
| 4861 | else => unreachable, | |
| 4862 | } | |
| 4863 | ||
| 4864 | out_buf = out_buf[curr_size..]; | |
| 4865 | total_written += curr_size; | |
| 4866 | curr_addr += curr_size; | |
| 4867 | } | |
| 4868 | ||
| 4869 | return total_written; | |
| 4870 | } | |
| 4871 | ||
| 4872 | pub fn readMem(task: MachTask, address: u64, buf: []u8) MachError!usize { | |
| 4873 | const count = buf.len; | |
| 4874 | var total_read: usize = 0; | |
| 4875 | var curr_addr = address; | |
| 4876 | const page_size = try MachTask.getPageSize(task); // TODO we probably can assume value here | |
| 4877 | var out_buf = buf[0..]; | |
| 4878 | ||
| 4879 | while (total_read < count) { | |
| 4880 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_read); | |
| 4881 | var curr_bytes_read: std.c.mach_msg_type_number_t = 0; | |
| 4882 | var vm_memory: std.c.vm_offset_t = undefined; | |
| 4883 | switch (getKernError(std.c.mach_vm_read(task.port, curr_addr, curr_size, &vm_memory, &curr_bytes_read))) { | |
| 4884 | .SUCCESS => {}, | |
| 4885 | .FAILURE => return error.PermissionDenied, | |
| 4886 | else => |err| return unexpectedKernError(err), | |
| 4887 | } | |
| 4888 | ||
| 4889 | @memcpy(out_buf[0..curr_bytes_read], @as([*]const u8, @ptrFromInt(vm_memory))); | |
| 4890 | _ = std.c.vm_deallocate(std.c.mach_task_self(), vm_memory, curr_bytes_read); | |
| 4891 | ||
| 4892 | out_buf = out_buf[curr_bytes_read..]; | |
| 4893 | curr_addr += curr_bytes_read; | |
| 4894 | total_read += curr_bytes_read; | |
| 4895 | } | |
| 4896 | ||
| 4897 | return total_read; | |
| 4898 | } | |
| 4899 | ||
| 4900 | fn maxBytesLeftInPage(page_size: usize, address: u64, count: usize) usize { | |
| 4901 | var left = count; | |
| 4902 | if (page_size > 0) { | |
| 4903 | const page_offset = address % page_size; | |
| 4904 | const bytes_left_in_page = page_size - page_offset; | |
| 4905 | if (count > bytes_left_in_page) { | |
| 4906 | left = bytes_left_in_page; | |
| 4907 | } | |
| 4908 | } | |
| 4909 | return left; | |
| 4910 | } | |
| 4911 | ||
| 4912 | fn getPageSize(task: MachTask) MachError!usize { | |
| 4913 | if (task.isValid()) { | |
| 4914 | var info_count = std.c.TASK_VM_INFO_COUNT; | |
| 4915 | var vm_info: std.c.task_vm_info_data_t = undefined; | |
| 4916 | switch (getKernError(std.c.task_info( | |
| 4917 | task.port, | |
| 4918 | std.c.TASK_VM_INFO, | |
| 4919 | @as(std.c.task_info_t, @ptrCast(&vm_info)), | |
| 4920 | &info_count, | |
| 4921 | ))) { | |
| 4922 | .SUCCESS => return @as(usize, @intCast(vm_info.page_size)), | |
| 4923 | else => {}, | |
| 4924 | } | |
| 4925 | } | |
| 4926 | var page_size: std.c.vm_size_t = undefined; | |
| 4927 | switch (getKernError(std.c._host_page_size(std.c.mach_host_self(), &page_size))) { | |
| 4928 | .SUCCESS => return page_size, | |
| 4929 | else => |err| return unexpectedKernError(err), | |
| 4930 | } | |
| 4931 | } | |
| 4932 | ||
| 4933 | pub fn basicTaskInfo(task: MachTask) MachError!std.c.mach_task_basic_info { | |
| 4934 | var info: std.c.mach_task_basic_info = undefined; | |
| 4935 | var count = std.c.MACH_TASK_BASIC_INFO_COUNT; | |
| 4936 | switch (getKernError(std.c.task_info( | |
| 4937 | task.port, | |
| 4938 | std.c.MACH_TASK_BASIC_INFO, | |
| 4939 | @as(std.c.task_info_t, @ptrCast(&info)), | |
| 4940 | &count, | |
| 4941 | ))) { | |
| 4942 | .SUCCESS => return info, | |
| 4943 | else => |err| return unexpectedKernError(err), | |
| 4944 | } | |
| 4945 | } | |
| 4946 | ||
| 4947 | pub fn @"resume"(task: MachTask) MachError!void { | |
| 4948 | switch (getKernError(std.c.task_resume(task.port))) { | |
| 4949 | .SUCCESS => {}, | |
| 4950 | else => |err| return unexpectedKernError(err), | |
| 4951 | } | |
| 4952 | } | |
| 4953 | ||
| 4954 | pub fn @"suspend"(task: MachTask) MachError!void { | |
| 4955 | switch (getKernError(std.c.task_suspend(task.port))) { | |
| 4956 | .SUCCESS => {}, | |
| 4957 | else => |err| return unexpectedKernError(err), | |
| 4958 | } | |
| 4959 | } | |
| 4960 | ||
| 4961 | const ThreadList = struct { | |
| 4962 | buf: []MachThread, | |
| 4963 | ||
| 4964 | pub fn deinit(list: ThreadList) void { | |
| 4965 | const self_task = machTaskForSelf(); | |
| 4966 | _ = std.c.vm_deallocate( | |
| 4967 | self_task.port, | |
| 4968 | @intFromPtr(list.buf.ptr), | |
| 4969 | @as(std.c.vm_size_t, @intCast(list.buf.len * @sizeOf(std.c.mach_port_t))), | |
| 4970 | ); | |
| 4971 | } | |
| 4972 | }; | |
| 4973 | ||
| 4974 | pub fn getThreads(task: MachTask) MachError!ThreadList { | |
| 4975 | var thread_list: std.c.mach_port_array_t = undefined; | |
| 4976 | var thread_count: std.c.mach_msg_type_number_t = undefined; | |
| 4977 | switch (getKernError(std.c.task_threads(task.port, &thread_list, &thread_count))) { | |
| 4978 | .SUCCESS => return ThreadList{ .buf = @as([*]MachThread, @ptrCast(thread_list))[0..thread_count] }, | |
| 4979 | else => |err| return unexpectedKernError(err), | |
| 4980 | } | |
| 4981 | } | |
| 4982 | }; | |
| 4983 | ||
| 4984 | pub const MachThread = extern struct { | |
| 4985 | port: std.c.mach_port_t, | |
| 4986 | ||
| 4987 | pub fn isValid(thread: MachThread) bool { | |
| 4988 | return thread.port != std.c.THREAD_NULL; | |
| 4989 | } | |
| 4990 | ||
| 4991 | pub fn getBasicInfo(thread: MachThread) MachError!std.c.thread_basic_info { | |
| 4992 | var info: std.c.thread_basic_info = undefined; | |
| 4993 | var count = std.c.THREAD_BASIC_INFO_COUNT; | |
| 4994 | switch (getKernError(std.c.thread_info( | |
| 4995 | thread.port, | |
| 4996 | std.c.THREAD_BASIC_INFO, | |
| 4997 | @as(std.c.thread_info_t, @ptrCast(&info)), | |
| 4998 | &count, | |
| 4999 | ))) { | |
| 5000 | .SUCCESS => return info, | |
| 5001 | else => |err| return unexpectedKernError(err), | |
| 5002 | } | |
| 5003 | } | |
| 5004 | ||
| 5005 | pub fn getIdentifierInfo(thread: MachThread) MachError!std.c.thread_identifier_info { | |
| 5006 | var info: std.c.thread_identifier_info = undefined; | |
| 5007 | var count = std.c.THREAD_IDENTIFIER_INFO_COUNT; | |
| 5008 | switch (getKernError(std.c.thread_info( | |
| 5009 | thread.port, | |
| 5010 | std.c.THREAD_IDENTIFIER_INFO, | |
| 5011 | @as(std.c.thread_info_t, @ptrCast(&info)), | |
| 5012 | &count, | |
| 5013 | ))) { | |
| 5014 | .SUCCESS => return info, | |
| 5015 | else => |err| return unexpectedKernError(err), | |
| 5016 | } | |
| 5017 | } | |
| 5018 | }; | |
| 5019 | ||
| 5020 | pub fn machTaskForPid(pid: std.c.pid_t) MachError!MachTask { | |
| 5021 | var port: std.c.mach_port_name_t = undefined; | |
| 5022 | switch (getKernError(std.c.task_for_pid(std.c.mach_task_self(), pid, &port))) { | |
| 5023 | .SUCCESS => {}, | |
| 5024 | .FAILURE => return error.PermissionDenied, | |
| 5025 | else => |err| return unexpectedKernError(err), | |
| 5026 | } | |
| 5027 | return MachTask{ .port = port }; | |
| 5028 | } | |
| 5029 | ||
| 5030 | pub fn machTaskForSelf() MachTask { | |
| 5031 | return .{ .port = std.c.mach_task_self() }; | |
| 5032 | } | |
| 5033 | ||
| 5034 | pub fn getKernError(err: std.c.kern_return_t) KernE { | |
| 5035 | return @as(KernE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err)))))); | |
| 5036 | } | |
| 5037 | ||
| 5038 | pub fn unexpectedKernError(err: KernE) std.posix.UnexpectedError { | |
| 5039 | if (std.posix.unexpected_error_tracing) { | |
| 5040 | std.debug.print("unexpected error: {d}\n", .{@intFromEnum(err)}); | |
| 5041 | std.debug.dumpCurrentStackTrace(null); | |
| 5042 | } | |
| 5043 | return error.Unexpected; | |
| 5044 | } | |
| 5045 | ||
| 5046 | /// Kernel return values | |
| 5047 | pub const KernE = enum(u32) { | |
| 5048 | SUCCESS = 0, | |
| 5049 | /// Specified address is not currently valid | |
| 5050 | INVALID_ADDRESS = 1, | |
| 5051 | /// Specified memory is valid, but does not permit the | |
| 5052 | /// required forms of access. | |
| 5053 | PROTECTION_FAILURE = 2, | |
| 5054 | /// The address range specified is already in use, or | |
| 5055 | /// no address range of the size specified could be | |
| 5056 | /// found. | |
| 5057 | NO_SPACE = 3, | |
| 5058 | /// The function requested was not applicable to this | |
| 5059 | /// type of argument, or an argument is invalid | |
| 5060 | INVALID_ARGUMENT = 4, | |
| 5061 | /// The function could not be performed. A catch-all. | |
| 5062 | FAILURE = 5, | |
| 5063 | /// A system resource could not be allocated to fulfill | |
| 5064 | /// this request. This failure may not be permanent. | |
| 5065 | RESOURCE_SHORTAGE = 6, | |
| 5066 | /// The task in question does not hold receive rights | |
| 5067 | /// for the port argument. | |
| 5068 | NOT_RECEIVER = 7, | |
| 5069 | /// Bogus access restriction. | |
| 5070 | NO_ACCESS = 8, | |
| 5071 | /// During a page fault, the target address refers to a | |
| 5072 | /// memory object that has been destroyed. This | |
| 5073 | /// failure is permanent. | |
| 5074 | MEMORY_FAILURE = 9, | |
| 5075 | /// During a page fault, the memory object indicated | |
| 5076 | /// that the data could not be returned. This failure | |
| 5077 | /// may be temporary; future attempts to access this | |
| 5078 | /// same data may succeed, as defined by the memory | |
| 5079 | /// object. | |
| 5080 | MEMORY_ERROR = 10, | |
| 5081 | /// The receive right is already a member of the portset. | |
| 5082 | ALREADY_IN_SET = 11, | |
| 5083 | /// The receive right is not a member of a port set. | |
| 5084 | NOT_IN_SET = 12, | |
| 5085 | /// The name already denotes a right in the task. | |
| 5086 | NAME_EXISTS = 13, | |
| 5087 | /// The operation was aborted. Ipc code will | |
| 5088 | /// catch this and reflect it as a message error. | |
| 5089 | ABORTED = 14, | |
| 5090 | /// The name doesn't denote a right in the task. | |
| 5091 | INVALID_NAME = 15, | |
| 5092 | /// Target task isn't an active task. | |
| 5093 | INVALID_TASK = 16, | |
| 5094 | /// The name denotes a right, but not an appropriate right. | |
| 5095 | INVALID_RIGHT = 17, | |
| 5096 | /// A blatant range error. | |
| 5097 | INVALID_VALUE = 18, | |
| 5098 | /// Operation would overflow limit on user-references. | |
| 5099 | UREFS_OVERFLOW = 19, | |
| 5100 | /// The supplied (port) capability is improper. | |
| 5101 | INVALID_CAPABILITY = 20, | |
| 5102 | /// The task already has send or receive rights | |
| 5103 | /// for the port under another name. | |
| 5104 | RIGHT_EXISTS = 21, | |
| 5105 | /// Target host isn't actually a host. | |
| 5106 | INVALID_HOST = 22, | |
| 5107 | /// An attempt was made to supply "precious" data | |
| 5108 | /// for memory that is already present in a | |
| 5109 | /// memory object. | |
| 5110 | MEMORY_PRESENT = 23, | |
| 5111 | /// A page was requested of a memory manager via | |
| 5112 | /// memory_object_data_request for an object using | |
| 5113 | /// a MEMORY_OBJECT_COPY_CALL strategy, with the | |
| 5114 | /// VM_PROT_WANTS_COPY flag being used to specify | |
| 5115 | /// that the page desired is for a copy of the | |
| 5116 | /// object, and the memory manager has detected | |
| 5117 | /// the page was pushed into a copy of the object | |
| 5118 | /// while the kernel was walking the shadow chain | |
| 5119 | /// from the copy to the object. This error code | |
| 5120 | /// is delivered via memory_object_data_error | |
| 5121 | /// and is handled by the kernel (it forces the | |
| 5122 | /// kernel to restart the fault). It will not be | |
| 5123 | /// seen by users. | |
| 5124 | MEMORY_DATA_MOVED = 24, | |
| 5125 | /// A strategic copy was attempted of an object | |
| 5126 | /// upon which a quicker copy is now possible. | |
| 5127 | /// The caller should retry the copy using | |
| 5128 | /// vm_object_copy_quickly. This error code | |
| 5129 | /// is seen only by the kernel. | |
| 5130 | MEMORY_RESTART_COPY = 25, | |
| 5131 | /// An argument applied to assert processor set privilege | |
| 5132 | /// was not a processor set control port. | |
| 5133 | INVALID_PROCESSOR_SET = 26, | |
| 5134 | /// The specified scheduling attributes exceed the thread's | |
| 5135 | /// limits. | |
| 5136 | POLICY_LIMIT = 27, | |
| 5137 | /// The specified scheduling policy is not currently | |
| 5138 | /// enabled for the processor set. | |
| 5139 | INVALID_POLICY = 28, | |
| 5140 | /// The external memory manager failed to initialize the | |
| 5141 | /// memory object. | |
| 5142 | INVALID_OBJECT = 29, | |
| 5143 | /// A thread is attempting to wait for an event for which | |
| 5144 | /// there is already a waiting thread. | |
| 5145 | ALREADY_WAITING = 30, | |
| 5146 | /// An attempt was made to destroy the default processor | |
| 5147 | /// set. | |
| 5148 | DEFAULT_SET = 31, | |
| 5149 | /// An attempt was made to fetch an exception port that is | |
| 5150 | /// protected, or to abort a thread while processing a | |
| 5151 | /// protected exception. | |
| 5152 | EXCEPTION_PROTECTED = 32, | |
| 5153 | /// A ledger was required but not supplied. | |
| 5154 | INVALID_LEDGER = 33, | |
| 5155 | /// The port was not a memory cache control port. | |
| 5156 | INVALID_MEMORY_CONTROL = 34, | |
| 5157 | /// An argument supplied to assert security privilege | |
| 5158 | /// was not a host security port. | |
| 5159 | INVALID_SECURITY = 35, | |
| 5160 | /// thread_depress_abort was called on a thread which | |
| 5161 | /// was not currently depressed. | |
| 5162 | NOT_DEPRESSED = 36, | |
| 5163 | /// Object has been terminated and is no longer available | |
| 5164 | TERMINATED = 37, | |
| 5165 | /// Lock set has been destroyed and is no longer available. | |
| 5166 | LOCK_SET_DESTROYED = 38, | |
| 5167 | /// The thread holding the lock terminated before releasing | |
| 5168 | /// the lock | |
| 5169 | LOCK_UNSTABLE = 39, | |
| 5170 | /// The lock is already owned by another thread | |
| 5171 | LOCK_OWNED = 40, | |
| 5172 | /// The lock is already owned by the calling thread | |
| 5173 | LOCK_OWNED_SELF = 41, | |
| 5174 | /// Semaphore has been destroyed and is no longer available. | |
| 5175 | SEMAPHORE_DESTROYED = 42, | |
| 5176 | /// Return from RPC indicating the target server was | |
| 5177 | /// terminated before it successfully replied | |
| 5178 | RPC_SERVER_TERMINATED = 43, | |
| 5179 | /// Terminate an orphaned activation. | |
| 5180 | RPC_TERMINATE_ORPHAN = 44, | |
| 5181 | /// Allow an orphaned activation to continue executing. | |
| 5182 | RPC_CONTINUE_ORPHAN = 45, | |
| 5183 | /// Empty thread activation (No thread linked to it) | |
| 5184 | NOT_SUPPORTED = 46, | |
| 5185 | /// Remote node down or inaccessible. | |
| 5186 | NODE_DOWN = 47, | |
| 5187 | /// A signalled thread was not actually waiting. | |
| 5188 | NOT_WAITING = 48, | |
| 5189 | /// Some thread-oriented operation (semaphore_wait) timed out | |
| 5190 | OPERATION_TIMED_OUT = 49, | |
| 5191 | /// During a page fault, indicates that the page was rejected | |
| 5192 | /// as a result of a signature check. | |
| 5193 | CODESIGN_ERROR = 50, | |
| 5194 | /// The requested property cannot be changed at this time. | |
| 5195 | POLICY_STATIC = 51, | |
| 5196 | /// The provided buffer is of insufficient size for the requested data. | |
| 5197 | INSUFFICIENT_BUFFER_SIZE = 52, | |
| 5198 | /// Denied by security policy | |
| 5199 | DENIED = 53, | |
| 5200 | /// The KC on which the function is operating is missing | |
| 5201 | MISSING_KC = 54, | |
| 5202 | /// The KC on which the function is operating is invalid | |
| 5203 | INVALID_KC = 55, | |
| 5204 | /// A search or query operation did not return a result | |
| 5205 | NOT_FOUND = 56, | |
| 5206 | _, | |
| 5207 | }; |