]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/corpses/corpse.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / osfmk / corpses / corpse.c
index 2941e21254a3393aad5f436cb8fa40cafcdcf564..73448a1f5717d8d77db4067a25eba0780e53e2cb 100644 (file)
 /*
  * Corpses Overview
  * ================
 /*
  * Corpses Overview
  * ================
- * 
+ *
  * A corpse is a state of process that is past the point of its death. This means that process has
  * completed all its termination operations like releasing file descriptors, mach ports, sockets and
  * other constructs used to identify a process. For all the processes this mimics the behavior as if
  * the process has died and no longer available by any means.
  * A corpse is a state of process that is past the point of its death. This means that process has
  * completed all its termination operations like releasing file descriptors, mach ports, sockets and
  * other constructs used to identify a process. For all the processes this mimics the behavior as if
  * the process has died and no longer available by any means.
- * 
+ *
  * Why do we need Corpses?
  * -----------------------
  * For crash inspection we need to inspect the state and data that is associated with process so that
  * crash reporting infrastructure can build backtraces, find leaks etc. For example a crash
  * Why do we need Corpses?
  * -----------------------
  * For crash inspection we need to inspect the state and data that is associated with process so that
  * crash reporting infrastructure can build backtraces, find leaks etc. For example a crash
- * 
+ *
  * Corpses functionality in kernel
  * ===============================
  * The corpse functionality is an extension of existing exception reporting mechanisms we have. The
  * Corpses functionality in kernel
  * ===============================
  * The corpse functionality is an extension of existing exception reporting mechanisms we have. The
@@ -49,7 +49,7 @@
  * notification the exception is not handled, then the process begins the death operations and during
  * proc_prepareexit, we decide to create a corpse for inspection. Following is a sample run through
  * of events and data shuffling that happens when corpses is enabled.
  * notification the exception is not handled, then the process begins the death operations and during
  * proc_prepareexit, we decide to create a corpse for inspection. Following is a sample run through
  * of events and data shuffling that happens when corpses is enabled.
- * 
+ *
  *   * a process causes an exception during normal execution of threads.
  *   * The exception generated by either mach(e.g GUARDED_MARCHPORT) or bsd(eg SIGABORT, GUARDED_FD
  *     etc) side is passed through the exception_triage() function to follow the thread -> task -> host
  *   * a process causes an exception during normal execution of threads.
  *   * The exception generated by either mach(e.g GUARDED_MARCHPORT) or bsd(eg SIGABORT, GUARDED_FD
  *     etc) side is passed through the exception_triage() function to follow the thread -> task -> host
@@ -78,8 +78,8 @@
  *     inspection flag set are just bounced to another holding queue (crashed_threads_queue).
  *     Only after the corpse notification these are pulled out from holding queue and enqueued
  *     back to termination queue
  *     inspection flag set are just bounced to another holding queue (crashed_threads_queue).
  *     Only after the corpse notification these are pulled out from holding queue and enqueued
  *     back to termination queue
- * 
- * 
+ *
+ *
  * Corpse info format
  * ==================
  * The kernel (task_mark_corpse()) makes a vm allocation in the dead task's vm space (with tag
  * Corpse info format
  * ==================
  * The kernel (task_mark_corpse()) makes a vm allocation in the dead task's vm space (with tag
@@ -88,7 +88,7 @@
  *   * bsd proc exit path may write down pid, parent pid, number of file descriptors etc
  *   * mach side may append data regarding ledger usage, memory stats etc
  * See detailed info about the memory structure and format in kern_cdata.h documentation.
  *   * bsd proc exit path may write down pid, parent pid, number of file descriptors etc
  *   * mach side may append data regarding ledger usage, memory stats etc
  * See detailed info about the memory structure and format in kern_cdata.h documentation.
- * 
+ *
  * Configuring Corpses functionality
  * =================================
  *   boot-arg: -no_corpses disables the corpse generation. This can be added/removed without affecting
  * Configuring Corpses functionality
  * =================================
  *   boot-arg: -no_corpses disables the corpse generation. This can be added/removed without affecting
@@ -98,7 +98,7 @@
  *     by system.
  *   CORPSEINFO_ALLOCATION_SIZE: is the default size of vm allocation. If in future there is much more
  *     data to be put in, then please re-tune this parameter.
  *     by system.
  *   CORPSEINFO_ALLOCATION_SIZE: is the default size of vm allocation. If in future there is much more
  *     data to be put in, then please re-tune this parameter.
- * 
+ *
  * Debugging/Visibility
  * ====================
  *   * lldbmacros for thread and task summary are updated to show "C" flag for corpse task/threads.
  * Debugging/Visibility
  * ====================
  *   * lldbmacros for thread and task summary are updated to show "C" flag for corpse task/threads.
  *     and holding queue (dumpcrashed_thread_queue).
  *   * In case of corpse creation is disabled of ignored then the system log is updated with
  *     printf data with reason.
  *     and holding queue (dumpcrashed_thread_queue).
  *   * In case of corpse creation is disabled of ignored then the system log is updated with
  *     printf data with reason.
- * 
+ *
  * Limitations of Corpses
  * ======================
  *   With holding off memory for inspection, it creates vm pressure which might not be desirable
  *   on low memory devices. There are limits to max corpses being inspected at a time which is
  *   marked by TOTAL_CORPSES_ALLOWED.
  * Limitations of Corpses
  * ======================
  *   With holding off memory for inspection, it creates vm pressure which might not be desirable
  *   on low memory devices. There are limits to max corpses being inspected at a time which is
  *   marked by TOTAL_CORPSES_ALLOWED.
- * 
+ *
  */
 
 
  */
 
 
@@ -158,19 +158,25 @@ int exc_via_corpse_forking = 1;
 /* bootarg to generate corpse for fatal high memory watermark violation */
 int corpse_for_fatal_memkill = 1;
 
 /* bootarg to generate corpse for fatal high memory watermark violation */
 int corpse_for_fatal_memkill = 1;
 
-#ifdef __arm__
-static inline int IS_64BIT_PROCESS(__unused void *p) { return 0; }
+#ifdef  __arm__
+static inline int
+IS_64BIT_PROCESS(__unused void *p)
+{
+       return 0;
+}
 #else
 extern int IS_64BIT_PROCESS(void *);
 #endif /* __arm__ */
 extern void gather_populate_corpse_crashinfo(void *p, task_t task,
 #else
 extern int IS_64BIT_PROCESS(void *);
 #endif /* __arm__ */
 extern void gather_populate_corpse_crashinfo(void *p, task_t task,
-               mach_exception_data_type_t code, mach_exception_data_type_t subcode,
-               uint64_t *udata_buffer, int num_udata, void *reason);
+    mach_exception_data_type_t code, mach_exception_data_type_t subcode,
+    uint64_t *udata_buffer, int num_udata, void *reason);
 extern void *proc_find(int pid);
 extern int proc_rele(void *p);
 
 
 extern void *proc_find(int pid);
 extern int proc_rele(void *p);
 
 
-void corpses_init(){
+void
+corpses_init()
+{
        char temp_buf[20];
        int exc_corpse_forking;
        int fatal_memkill;
        char temp_buf[20];
        int exc_corpse_forking;
        int fatal_memkill;
@@ -189,7 +195,8 @@ void corpses_init(){
  * Routine: corpses_enabled
  * returns FALSE if not enabled
  */
  * Routine: corpses_enabled
  * returns FALSE if not enabled
  */
-boolean_t corpses_enabled()
+boolean_t
+corpses_enabled()
 {
        return corpse_enabled_config;
 }
 {
        return corpse_enabled_config;
 }
@@ -229,8 +236,8 @@ task_crashinfo_get_ref(uint16_t kcd_u_flags)
 
                // this reloads the value in oldgate
                if (atomic_compare_exchange_strong_explicit(&inflight_corpses,
 
                // this reloads the value in oldgate
                if (atomic_compare_exchange_strong_explicit(&inflight_corpses,
-                               &oldgate.value, newgate.value, memory_order_relaxed,
-                               memory_order_relaxed)) {
+                   &oldgate.value, newgate.value, memory_order_relaxed,
+                   memory_order_relaxed)) {
                        return KERN_SUCCESS;
                }
        }
                        return KERN_SUCCESS;
                }
        }
@@ -260,8 +267,8 @@ task_crashinfo_release_ref(uint16_t kcd_u_flags)
                }
                // this reloads the value in oldgate
                if (atomic_compare_exchange_strong_explicit(&inflight_corpses,
                }
                // this reloads the value in oldgate
                if (atomic_compare_exchange_strong_explicit(&inflight_corpses,
-                               &oldgate.value, newgate.value, memory_order_relaxed,
-                               memory_order_relaxed)) {
+                   &oldgate.value, newgate.value, memory_order_relaxed,
+                   memory_order_relaxed)) {
                        return KERN_SUCCESS;
                }
        }
                        return KERN_SUCCESS;
                }
        }
@@ -270,7 +277,7 @@ task_crashinfo_release_ref(uint16_t kcd_u_flags)
 
 kcdata_descriptor_t
 task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size,
 
 kcdata_descriptor_t
 task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size,
-               uint32_t kc_u_flags, unsigned kc_flags)
+    uint32_t kc_u_flags, unsigned kc_flags)
 {
        kcdata_descriptor_t kcdata;
 
 {
        kcdata_descriptor_t kcdata;
 
@@ -281,7 +288,7 @@ task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size,
        }
 
        kcdata = kcdata_memory_alloc_init(crash_data_p, TASK_CRASHINFO_BEGIN, size,
        }
 
        kcdata = kcdata_memory_alloc_init(crash_data_p, TASK_CRASHINFO_BEGIN, size,
-                       kc_flags);
+           kc_flags);
        if (kcdata) {
                kcdata->kcd_user_flags = kc_u_flags;
        } else if (kc_u_flags & CORPSE_CRASHINFO_HAS_REF) {
        if (kcdata) {
                kcdata->kcd_user_flags = kc_u_flags;
        } else if (kc_u_flags & CORPSE_CRASHINFO_HAS_REF) {
@@ -312,10 +319,11 @@ task_crashinfo_destroy(kcdata_descriptor_t data)
  * returns: crash info data attached to task.
  *          NULL if task is null or has no corpse info
  */
  * returns: crash info data attached to task.
  *          NULL if task is null or has no corpse info
  */
-kcdata_descriptor_t task_get_corpseinfo(task_t task)
+kcdata_descriptor_t
+task_get_corpseinfo(task_t task)
 {
        kcdata_descriptor_t retval = NULL;
 {
        kcdata_descriptor_t retval = NULL;
-       if (task != NULL){
+       if (task != NULL) {
                retval = task->corpse_info;
        }
        return retval;
                retval = task->corpse_info;
        }
        return retval;
@@ -363,17 +371,17 @@ task_purge_all_corpses(void)
        /* Iterate through all the corpse tasks and clear all map entries */
        queue_iterate(&corpse_tasks, task, task_t, corpse_tasks) {
                vm_map_remove(task->map,
        /* Iterate through all the corpse tasks and clear all map entries */
        queue_iterate(&corpse_tasks, task, task_t, corpse_tasks) {
                vm_map_remove(task->map,
-                             task->map->min_offset,
-                             task->map->max_offset,
-                             /*
-                              * Final cleanup:
-                              * + no unnesting
-                              * + remove immutable mappings
-                              * + allow gaps in the range
-                              */
-                             (VM_MAP_REMOVE_NO_UNNESTING |
-                              VM_MAP_REMOVE_IMMUTABLE |
-                              VM_MAP_REMOVE_GAPS_OK));
+                   task->map->min_offset,
+                   task->map->max_offset,
+                   /*
+                    * Final cleanup:
+                    * + no unnesting
+                    * + remove immutable mappings
+                    * + allow gaps in the range
+                    */
+                   (VM_MAP_REMOVE_NO_UNNESTING |
+                   VM_MAP_REMOVE_IMMUTABLE |
+                   VM_MAP_REMOVE_GAPS_OK));
        }
 
        lck_mtx_unlock(&tasks_corpse_lock);
        }
 
        lck_mtx_unlock(&tasks_corpse_lock);
@@ -478,7 +486,7 @@ task_enqueue_exception_with_corpse(
 
        /* Generate a corpse for the given task, will return with a ref on corpse task */
        kr = task_generate_corpse_internal(task, &new_task, &thread,
 
        /* Generate a corpse for the given task, will return with a ref on corpse task */
        kr = task_generate_corpse_internal(task, &new_task, &thread,
-                       etype, code[0], code[1], reason);
+           etype, code[0], code[1], reason);
        if (kr == KERN_SUCCESS) {
                if (thread == THREAD_NULL) {
                        return KERN_FAILURE;
        if (kr == KERN_SUCCESS) {
                if (thread == THREAD_NULL) {
                        return KERN_FAILURE;
@@ -529,7 +537,7 @@ task_generate_corpse_internal(
 #if CONFIG_MACF
        struct label *label = NULL;
 #endif
 #if CONFIG_MACF
        struct label *label = NULL;
 #endif
-       
+
        if (!corpses_enabled()) {
                return KERN_NOT_SUPPORTED;
        }
        if (!corpses_enabled()) {
                return KERN_NOT_SUPPORTED;
        }
@@ -553,10 +561,10 @@ task_generate_corpse_internal(
        is_64bit_addr = IS_64BIT_PROCESS(p);
        is_64bit_data = (task == TASK_NULL) ? is_64bit_addr : task_get_64bit_data(task);
        t_flags = TF_CORPSE_FORK |
        is_64bit_addr = IS_64BIT_PROCESS(p);
        is_64bit_data = (task == TASK_NULL) ? is_64bit_addr : task_get_64bit_data(task);
        t_flags = TF_CORPSE_FORK |
-                         TF_PENDING_CORPSE |
-                         TF_CORPSE |
-                         (is_64bit_addr ? TF_64B_ADDR : TF_NONE) |
-                         (is_64bit_data ? TF_64B_DATA : TF_NONE);
+           TF_PENDING_CORPSE |
+           TF_CORPSE |
+           (is_64bit_addr ? TF_64B_ADDR : TF_NONE) |
+           (is_64bit_data ? TF_64B_DATA : TF_NONE);
 
 #if CONFIG_MACF
        /* Create the corpse label credentials from the process. */
 
 #if CONFIG_MACF
        /* Create the corpse label credentials from the process. */
@@ -565,29 +573,29 @@ task_generate_corpse_internal(
 
        /* Create a task for corpse */
        kr = task_create_internal(task,
 
        /* Create a task for corpse */
        kr = task_create_internal(task,
-                               NULL,
-                               TRUE,
-                               is_64bit_addr,
-                               is_64bit_data,
-                               t_flags,
-                               TPF_NONE,
-                               &new_task);
+           NULL,
+           TRUE,
+           is_64bit_addr,
+           is_64bit_data,
+           t_flags,
+           TPF_NONE,
+           &new_task);
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
 
        /* Create and copy threads from task, returns a ref to thread */
        kr = task_duplicate_map_and_threads(task, p, new_task, &thread,
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
 
        /* Create and copy threads from task, returns a ref to thread */
        kr = task_duplicate_map_and_threads(task, p, new_task, &thread,
-                               &udata_buffer, &size, &num_udata);
+           &udata_buffer, &size, &num_udata);
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
 
        kr = task_collect_crash_info(new_task,
 #if CONFIG_MACF
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
 
        kr = task_collect_crash_info(new_task,
 #if CONFIG_MACF
-                                                                label,
+           label,
 #endif
 #endif
-                                                                TRUE);
+           TRUE);
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
        if (kr != KERN_SUCCESS) {
                goto error_task_generate_corpse;
        }
@@ -607,7 +615,7 @@ task_generate_corpse_internal(
 
        /* Populate the corpse blob, use the proc struct of task instead of corpse task */
        gather_populate_corpse_crashinfo(p, new_task,
 
        /* Populate the corpse blob, use the proc struct of task instead of corpse task */
        gather_populate_corpse_crashinfo(p, new_task,
-                       code, subcode, udata_buffer, num_udata, reason);
+           code, subcode, udata_buffer, num_udata, reason);
 
        /* Add it to global corpse task list */
        task_add_to_corpse_task_list(new_task);
 
        /* Add it to global corpse task list */
        task_add_to_corpse_task_list(new_task);
@@ -621,7 +629,7 @@ error_task_generate_corpse:
                mac_exc_free_label(label);
        }
 #endif
                mac_exc_free_label(label);
        }
 #endif
-       
+
        /* Release the proc reference */
        if (p != NULL) {
                proc_rele(p);
        /* Release the proc reference */
        if (p != NULL) {
                proc_rele(p);
@@ -722,7 +730,7 @@ task_map_corpse_info_64(
        }
        corpse_info_kernel = kcdata_memory_get_begin_addr(corpse_task->corpse_info);
        kr = mach_vm_allocate_kernel(task->map, &crash_data_ptr, size,
        }
        corpse_info_kernel = kcdata_memory_get_begin_addr(corpse_task->corpse_info);
        kr = mach_vm_allocate_kernel(task->map, &crash_data_ptr, size,
-                       VM_FLAGS_ANYWHERE, VM_MEMORY_CORPSEINFO);
+           VM_FLAGS_ANYWHERE, VM_MEMORY_CORPSEINFO);
        if (kr != KERN_SUCCESS) {
                return kr;
        }
        if (kr != KERN_SUCCESS) {
                return kr;
        }