本文共 12642 字,大约阅读时间需要 42 分钟。
//// main.m// MachPortDump//// Created by haidragon on 2019/6/10.// Copyright © 2019 haidragon. All rights reserved.//////#import////int main(int argc, const char * argv[]) {// @autoreleasepool {// // insert code here...// NSLog(@"Hello, World!");// }// return 0;//}#include #include #include #include #include #include #include #include #include #pragma mark ***** Compatibility Note#pragma mark ***** The Codestatic const char *gProgramName;static void PrintPortSetMembers(mach_port_t taskSendRight, mach_port_name_t portSetName)// For a given Mach port set within a given task, print the members// of the port set.{ kern_return_t err; kern_return_t junk; mach_port_name_array_t memberNames; mach_msg_type_number_t memberNamesCount; mach_msg_type_number_t memberIndex; memberNames = NULL; // Get an array of members. err = mach_port_get_set_status( taskSendRight, portSetName, &memberNames, &memberNamesCount ); // Iterate over the array, printing each one. Note that we print 6 members to // a line and we start every line except the second with enough spaces to // account for the information that we print that's common to each type // of output. if (err == KERN_SUCCESS) { fprintf(stdout, " "); for (memberIndex = 0; memberIndex < memberNamesCount; memberIndex++) { if ( (memberIndex != 0) && (memberIndex % 6) == 0) { // 6 columns of (8 characters plus space) // plus DNR column (3 chars) plus space fprintf(stdout, "\n%*s ", (6 * (8 + 1)) + 3 + 1, ""); } fprintf(stdout, "%#8x ", memberNames[memberIndex]); } } else { fprintf(stdout, "??? "); } // Clean up. if (memberNames != NULL) { junk = vm_deallocate(mach_task_self(), (vm_address_t) memberNames, memberNamesCount * sizeof(*memberNames)); assert(junk == KERN_SUCCESS); }}static void PrintPortReceiveStatus(mach_port_t taskSendRight, mach_port_name_t receiveRight)// Print information about the Mach receive right in the specified// task.{ kern_return_t err; mach_port_status_t status; mach_msg_type_number_t statusCount; // Get information about the the right. statusCount = MACH_PORT_RECEIVE_STATUS_COUNT; err = mach_port_get_attributes( taskSendRight, receiveRight, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t) &status, &statusCount ); assert( (err != KERN_SUCCESS) || (statusCount == MACH_PORT_RECEIVE_STATUS_COUNT) ); // Print it, as a group of flags followed by 6 columns of numbers, // which are basically all counters. if (err == KERN_SUCCESS) { fprintf( stdout, "%c%c%c ", (status.mps_nsrequest ? 'N' : '-'), (status.mps_pdrequest ? 'P' : '-'), (status.mps_srights ? 'S' : '-') ); fprintf( stdout, "%8u %8u %8u %8u %8u %8u", status.mps_seqno, status.mps_mscount, status.mps_qlimit, status.mps_msgcount, status.mps_sorights, status.mps_pset ); // The kernel always sets mps_flags to 0, so we don't both printing it. assert(status.mps_flags == 0); } else { fprintf( stdout, "??? %8s %8s %8s %8s %8s %8s", "???", "???", "???", "???", "???", "???" ); }}static kern_return_t PrintProcessPortSpace(pid_t pid, bool verbose)// Prints port rights owned by the specified process.{ kern_return_t err; kern_return_t junk; mach_port_t taskSendRight; mach_port_name_array_t rightNames; mach_msg_type_number_t rightNamesCount = 0; mach_port_type_array_t rightTypes; mach_msg_type_number_t rightTypesCount = 0; unsigned int i; taskSendRight = MACH_PORT_NULL; rightNames = NULL; rightTypes = NULL; // Get the task control port for the process. err = task_for_pid(mach_task_self(), pid, &taskSendRight); if (err != KERN_SUCCESS) { fprintf(stderr, "%s: Could not attach to process %lld (%#08x).\n", gProgramName, (long long) pid, err); } // Get a snapshot of the port name space for the task. if (err == KERN_SUCCESS) { err = mach_port_names(taskSendRight, &rightNames, &rightNamesCount, &rightTypes, &rightTypesCount); } if (err == KERN_SUCCESS) { if ( rightNamesCount != rightTypesCount ) { fprintf(stderr, "%s: Count mismatch (%u/%u)\n", gProgramName, rightNamesCount, rightTypesCount); err = KERN_FAILURE; } } // Print that snapshot. if (err == KERN_SUCCESS) { fprintf(stdout, " Name Send Receive SendOnce PortSet DeadName DNR"); if (verbose) { fprintf(stdout, " flg seqno mscount qlimit msgcount sorights pset"); } fprintf(stdout, "\n"); fprintf(stdout, " ---- ---- ------- -------- ------- -------- ---"); if (verbose) { fprintf(stdout, " --- ----- ------- ------ -------- -------- ----"); } fprintf(stdout, "\n"); // For each name, print a reference count of each type of right. If running // verbose, print other information as well. for (i = 0; i < rightNamesCount; i++) { mach_port_right_t right; // We print the right name in hex because it makes it easier to // see the index and generation fields. See for // information about this. fprintf(stdout, "%#8x ", rightNames[i]); for (right = MACH_PORT_RIGHT_SEND; right <= MACH_PORT_RIGHT_DEAD_NAME; right++) { mach_port_urefs_t refCount; // If the rightTypes for this name has the bit associated // with this type of right set (that is, if the name // references this type of right), get the name's reference // for this right and print it. Otherwise just print an // empty string to keep the columns lined up. if (rightTypes[i] & MACH_PORT_TYPE(right)) { err = mach_port_get_refs(taskSendRight, rightNames[i], right, &refCount); if (err == KERN_SUCCESS) { fprintf(stdout, "%8d ", refCount); } else { fprintf(stdout, "%8s ", "???"); } } else { fprintf(stdout, "%8s ", ""); } } if ( rightTypes[i] & MACH_PORT_TYPE_DNREQUEST ) { fprintf(stdout, "yes "); } else { fprintf(stdout, " "); } if (verbose) { if (rightTypes[i] & MACH_PORT_TYPE_PORT_SET) { PrintPortSetMembers(taskSendRight, rightNames[i]); } else if (rightTypes[i] & MACH_PORT_TYPE_RECEIVE) { PrintPortReceiveStatus(taskSendRight, rightNames[i]); } } fprintf(stdout, "\n"); } } // Clean up. if (rightNames != NULL) { junk = vm_deallocate(mach_task_self(), (vm_address_t) rightNames, rightNamesCount * sizeof(*rightNames)); assert(junk == KERN_SUCCESS); } if (rightTypes != NULL) { junk = vm_deallocate(mach_task_self(), (vm_address_t) rightTypes, rightTypesCount * sizeof(*rightTypes)); assert(junk == KERN_SUCCESS); } if (taskSendRight != MACH_PORT_NULL) { junk = mach_port_deallocate(mach_task_self(), taskSendRight); assert(junk == KERN_SUCCESS); } return err;}typedef struct kinfo_proc kinfo_proc;static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount)// Returns a list of all BSD processes on the system. This routine// allocates the list and puts it in *procList and a count of the// number of entries in *procCount. You are responsible for freeing// this list (use "free" from System framework).// On success, the function returns 0.// On error, the function returns a BSD errno value.{ int err; kinfo_proc * result; bool done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); *procCount = 0; // We start by calling sysctl with result == NULL and length == 0. // That will succeed, and set length to the appropriate length. // We then allocate a buffer of that size and call sysctl again // with that buffer. If that succeeds, we're done. If that fails // with ENOMEM, we have to throw away our buffer and loop. Note // that the loop causes use to call sysctl with NULL again; this // is necessary because the ENOMEM failure case sets length to // the amount of data returned, not the amount of data that // could have been returned. result = NULL; done = false; do { assert(result == NULL); // Call sysctl with a NULL buffer. length = 0; err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); if (err == -1) { err = errno; } // Allocate an appropriately sized buffer based on the results // from the previous call. if (err == 0) { result = malloc(length); if (result == NULL) { err = ENOMEM; } } // Call sysctl again with the new buffer. If we get an ENOMEM // error, toss away our buffer and start again. if (err == 0) { err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0); if (err == -1) { err = errno; } if (err == 0) { done = true; } else if (err == ENOMEM) { assert(result != NULL); free(result); result = NULL; err = 0; } } } while (err == 0 && ! done); // Clean up and establish post conditions. if (err != 0 && result != NULL) { free(result); result = NULL; } *procList = result; if (err == 0) { *procCount = length / sizeof(kinfo_proc); } assert( (err == 0) == (*procList != NULL) ); return err;}static int FindProcessByName(const char *processName, pid_t *pid)// Find the process that best matches processName and return// its PID. It first tries to find an exact match; if that fails// it tries to find a substring match; if that fails it checks// whether processName is a number and returns that as the PID.//// On entry, processName must not be NULL, and it must not be the// empty string. pid must not be NULL.// On success, *pid will be the process ID of the found process.// On error, *pid is undefined.{ int err; int foundCount; kinfo_proc * processList; size_t processCount; size_t processIndex; assert(processName != NULL); assert(processName[0] != 0); // needed for strstr to behave assert(pid != NULL); processList = NULL; foundCount = 0; // Get the list of all processes. err = GetBSDProcessList(&processList, &processCount); if (err == 0) { // Search for an exact match. for (processIndex = 0; processIndex < processCount; processIndex++) { if ( strcmp(processList[processIndex].kp_proc.p_comm, processName) == 0 ) { *pid = processList[processIndex].kp_proc.p_pid; foundCount = 1; break; } } // If that failed, search for a substring match. if (foundCount == 0) { for (processIndex = 0; processIndex < processCount; processIndex++) { if ( strstr(processList[processIndex].kp_proc.p_comm, processName) != NULL ) { *pid = processList[processIndex].kp_proc.p_pid; foundCount += 1; } } } // If we found more than 1, that's ambiguous and we error out. if (foundCount > 1) { fprintf(stderr, "%s: '%s' does not denote a unique process.\n", gProgramName, processName); err = EINVAL; } } // If still not found, try processName as a PID. if ( (err == 0) && (foundCount == 0) ) { char * firstInvalid; *pid = (pid_t) strtol(processName, &firstInvalid, 10); if ( (processName[0] == 0) || (*firstInvalid != 0) ) { err = EINVAL; } } free(processList); return err;}static void PrintUsage(void){ fprintf(stderr, "usage: %s [options] [ [ pid | name ]... ]\n", gProgramName); fprintf(stderr, " Send, Receive, SendOnce, PortSet, DeadName = right reference counts\n"); fprintf(stderr, " DNR = dead name request\n"); fprintf(stderr, " -w wide output, with lots of extra info\n"); fprintf(stderr, " flg = N (no senders) P (port dead) S (send rights)\n"); fprintf(stderr, " seqno = sequence number\n"); fprintf(stderr, " mscount = make-send count\n"); fprintf(stderr, " qlimit = queue limit\n"); fprintf(stderr, " msgcount = message count\n"); fprintf(stderr, " sorights = send-once right count\n"); fprintf(stderr, " pset = port set count\n");}int main(int argc, char * argv[]){ kern_return_t err = 0; bool verbose; int ch; int argIndex; // Set gProgramName to the last path component of argv[0] gProgramName = strrchr(argv[0], '/'); if (gProgramName == NULL) { gProgramName = argv[0]; } else { gProgramName += 1; } // Parse our options. verbose = false; do { ch = getopt(argc, argv, "w"); if (ch != -1) { switch (ch) { case 'w': verbose = true; break; case '?': default: PrintUsage(); exit(EXIT_FAILURE); break; } } } while (ch != -1); // Handle the remaining arguments. If none, we work against ourselves. // Otherwise each string is treated as a process name, and we look that // up using FindProcessByName. if (argv[optind] == NULL) { err = PrintProcessPortSpace(getpid(), verbose); } else { for (argIndex = optind; argIndex < argc; argIndex++) { pid_t pid = 0; if (argIndex > optind) { fprintf(stdout, "\n"); } if (argv[argIndex][0] == 0) { err = EINVAL; } else { err = FindProcessByName(argv[argIndex], &pid); } if (err == 0) { fprintf(stdout, "Mach ports for '%s' (%lld):\n", argv[argIndex], (long long) pid); fprintf(stdout, "\n"); err = PrintProcessPortSpace(pid, verbose); } if (err != 0) { break; } } } if (err != 0) { fprintf(stderr, "%s: Failed with error %d.\n", gProgramName, err); } return (err == 0) ? EXIT_SUCCESS : EXIT_FAILURE;}
转载于:https://blog.51cto.com/haidragon/2407067