Loading...
src/stack_logging_disk.c libmalloc-116 libmalloc-140.1.1
--- libmalloc/libmalloc-116/src/stack_logging_disk.c
+++ libmalloc/libmalloc-140.1.1/src/stack_logging_disk.c
@@ -22,6 +22,7 @@
  */
 
 #include "internal.h"
+#include "radix_tree.h"
 
 #pragma mark -
 #pragma mark Defines
@@ -141,6 +142,8 @@
 	uint32_t next_free_index_buffer_offset;
 	char index_buffer[STACK_LOGGING_BLOCK_WRITING_SIZE];
 	backtrace_uniquing_table *uniquing_table;
+	struct radix_tree *vm_stackid_table;
+	uint64_t vm_stackid_table_size;
 } stack_buffer_shared_memory;
 #pragma pack(pop)
 
@@ -162,6 +165,7 @@
 	uint64_t last_index_file_offset;
 	backtrace_uniquing_table uniquing_table_snapshot; // snapshot of the remote process' uniquing table
 	boolean_t lite_mode;
+	struct radix_tree *vm_stackid_table;
 } remote_index_cache;
 
 // for reading stack history information from remote processes:
@@ -222,6 +226,7 @@
 static const slot_parent slot_no_parent_refcount = 0xFFFFFFFF;				// 32 bits
 
 static _malloc_lock_s stack_logging_lock = _MALLOC_LOCK_INIT;
+static vm_address_t thread_doing_logging = 0;
 
 // single-thread access variables
 static stack_buffer_shared_memory *pre_write_buffers;
@@ -1027,6 +1032,8 @@
 			return false;
 		}
 
+		pre_write_buffers->vm_stackid_table = NULL;
+
 		uint64_t stack_buffer_sz = (uint64_t)round_page(sizeof(vm_address_t) * STACK_LOGGING_MAX_STACK_SIZE);
 		stack_buffer = (vm_address_t *)sld_allocate_pages(stack_buffer_sz);
 		if (!stack_buffer) {
@@ -1103,11 +1110,13 @@
 __malloc_lock_stack_logging()
 {
 	_malloc_lock_lock(&stack_logging_lock);
+	thread_doing_logging = (vm_address_t)_os_tsd_get_direct(__TSD_THREAD_SELF);
 }
 
 __attribute__((visibility("hidden"))) void
 __malloc_unlock_stack_logging()
 {
+	thread_doing_logging = 0;
 	_malloc_lock_unlock(&stack_logging_lock);
 }
 
@@ -1128,7 +1137,7 @@
 	}
 	
 	// skip stack frames after the malloc call
-	num_hot_to_skip += 4;
+	num_hot_to_skip += 3; // __disk_stack_logging_log_stack | __enter_stack_into_table_while_locked | thread_stack_pcs
 	
 	if (count <= num_hot_to_skip) {
 		// Oops!  Didn't get a valid backtrace from thread_stack_pcs().
@@ -1215,6 +1224,11 @@
 		uint32_t num_hot_to_skip)
 {
 	if (!stack_logging_enable_logging || stack_logging_postponed) {
+		return;
+	}
+
+	if (stack_logging_mode == stack_logging_mode_lite &&
+		!((type_flags & stack_logging_type_vm_allocate) ||(type_flags & stack_logging_type_vm_deallocate))) {
 		return;
 	}
 
@@ -1252,7 +1266,7 @@
 		}
 	}
 	if (type_flags & stack_logging_type_alloc || type_flags & stack_logging_type_vm_allocate) {
-		if (return_val == 0) {
+		if (return_val == 0 || return_val == (uintptr_t)MAP_FAILED) {
 			return; // alloc that failed
 		}
 		size = arg2;
@@ -1269,7 +1283,6 @@
 	type_flags &= stack_logging_valid_type_flags;
 
 	vm_address_t self_thread = (vm_address_t)_os_tsd_get_direct(__TSD_THREAD_SELF);
-	static vm_address_t thread_doing_logging = 0;
 
 	if (thread_doing_logging == self_thread) {
 		// Prevent a thread from deadlocking against itself if vm_allocate() or malloc()
@@ -1285,15 +1298,21 @@
 
 	thread_doing_logging = self_thread; // for preventing deadlock'ing on stack logging on a single thread
 
+	if (stack_logging_mode == stack_logging_mode_lite && (type_flags & stack_logging_type_vm_deallocate)) {
+		if (pre_write_buffers && pre_write_buffers->vm_stackid_table) {
+			radix_tree_delete(&pre_write_buffers->vm_stackid_table,
+							  trunc_page(ptr_arg), round_page(ptr_arg + size) - trunc_page(ptr_arg));
+			goto out;
+		}
+	}
+
 	// now actually begin
 	__prepare_to_log_stacks(false);
 
 	// since there could have been a fatal (to stack logging) error such as the log files not being created, check these variables
 	// before continuing
 	if (!stack_logging_enable_logging || stack_logging_postponed) {
-		thread_doing_logging = 0;
-		_malloc_lock_unlock(&stack_logging_lock);
-		return;
+		goto out;
 	}
 
 	if (type_flags & stack_logging_type_alloc) {
@@ -1308,18 +1327,35 @@
 		// *waves hand* the last allocation never occurred
 		pre_write_buffers->next_free_index_buffer_offset -= (uint32_t)sizeof(stack_logging_index_event);
 		last_logged_malloc_address = 0ul;
-
-		thread_doing_logging = 0;
-		_malloc_lock_unlock(&stack_logging_lock);
-		return;
-	}
-
-	uint64_t uniqueStackIdentifier = __enter_stack_into_table_while_locked(self_thread, num_hot_to_skip, true, 0);
+		goto out;
+	}
+
+	uint64_t uniqueStackIdentifier;
+	if (stack_logging_mode == stack_logging_mode_lite) {
+		uniqueStackIdentifier = __enter_stack_into_table_while_locked(self_thread, num_hot_to_skip, false, 1);
+	} else {
+		uniqueStackIdentifier = __enter_stack_into_table_while_locked(self_thread, num_hot_to_skip, true, 0);
+	}
 	
 	if (uniqueStackIdentifier == __invalid_stack_id) {
-		thread_doing_logging = 0;
-		_malloc_lock_unlock(&stack_logging_lock);
-		return;
+		goto out;
+	}
+
+	if (stack_logging_mode == stack_logging_mode_lite && (type_flags & stack_logging_type_vm_allocate)) {
+		if (pre_write_buffers) {
+			if (!pre_write_buffers->vm_stackid_table) {
+				pre_write_buffers->vm_stackid_table	= radix_tree_create();
+				pre_write_buffers->vm_stackid_table_size = radix_tree_size(pre_write_buffers->vm_stackid_table);
+			}
+			if (pre_write_buffers->vm_stackid_table) {
+				uint64_t address = return_val;
+				radix_tree_insert(&pre_write_buffers->vm_stackid_table,
+								  trunc_page(address), round_page(address+size) - trunc_page(address),
+								  uniqueStackIdentifier);
+				pre_write_buffers->vm_stackid_table_size = radix_tree_size(pre_write_buffers->vm_stackid_table);
+			}
+		}
+		goto out;
 	}
 
 	stack_logging_index_event current_index;
@@ -1349,6 +1385,7 @@
 			sizeof(stack_logging_index_event));
 	pre_write_buffers->next_free_index_buffer_offset += (uint32_t)sizeof(stack_logging_index_event);
 
+out:
 	thread_doing_logging = 0;
 	_malloc_lock_unlock(&stack_logging_lock);
 }
@@ -1699,6 +1736,16 @@
 					descriptors->remote_stack_buffer_shared_memory_address, descriptors->remote_pid);
 		}
 		cache->lite_mode = descriptors->task_uses_lite_mode;
+
+		if (cache->shmem && cache->shmem->vm_stackid_table) {
+			cache->vm_stackid_table = (struct radix_tree *)map_shared_memory_from_task(
+				descriptors->remote_task, (mach_vm_address_t) cache->shmem->vm_stackid_table, cache->shmem->vm_stackid_table_size);
+			if (!cache->vm_stackid_table) {
+				_malloc_printf(ASL_LEVEL_INFO,
+							   "warning: unable to map vm_stackid table from %llx in target process %d; no VM stack backtraces will be available.\n",
+							   (mach_vm_address_t) cache->shmem->vm_stackid_table, descriptors->remote_pid);
+			}
+		}
 	}
 
 	// suspend and see how much updating there is to do. there are three scenarios, listed below
@@ -2200,7 +2247,9 @@
 			} else {
 				// remote_fds[i].in_use_count is 0 so don't decrement it!
 				fclose(remote_fds[i].index_file_stream);
+				remote_fds[i].index_file_stream = NULL;
 				destroy_cache_for_file_streams(&remote_fds[i]);
+				remote_fds[i].remote_task = 0;
 			}
 			break;
 		}
@@ -2311,7 +2360,7 @@
 		return KERN_FAILURE;
 	}
 
-	return __mach_stack_logging_frames_for_uniqued_stack(task, located_file_position, stack_frames_buffer, max_stack_frames, count);
+	return __mach_stack_logging_get_frames_for_stackid(task, located_file_position, stack_frames_buffer, max_stack_frames, count, NULL);
 }
 
 kern_return_t
@@ -2408,12 +2457,48 @@
 	return err;
 }
 
+uint64_t
+__mach_stack_logging_stackid_for_vm_region(task_t task, mach_vm_address_t address)
+{
+	remote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);
+	if (remote_fd == NULL) {
+		return __invalid_stack_id;
+	}
+
+	kern_return_t err = update_cache_for_file_streams(remote_fd);
+	if (err != KERN_SUCCESS) {
+		release_file_streams_for_task(task);
+		return __invalid_stack_id;
+	}
+
+	uint64_t stackid = __invalid_stack_id;
+
+	if (remote_fd->cache && remote_fd->cache->vm_stackid_table) {
+		stackid = radix_tree_lookup(remote_fd->cache->vm_stackid_table, address);
+	}
+
+	release_file_streams_for_task(task);
+	return stackid;
+}
+
 kern_return_t
 __mach_stack_logging_frames_for_uniqued_stack(task_t task,
-		uint64_t stack_identifier,
-		mach_vm_address_t *stack_frames_buffer,
-		uint32_t max_stack_frames,
-		uint32_t *count)
+											  uint64_t stack_identifier,
+											  mach_vm_address_t *stack_frames_buffer,
+											  uint32_t max_stack_frames,
+											  uint32_t *count)
+{
+	return __mach_stack_logging_get_frames_for_stackid(task, stack_identifier, stack_frames_buffer, max_stack_frames, count, NULL);
+}
+
+
+kern_return_t
+__mach_stack_logging_get_frames_for_stackid(task_t task,
+											uint64_t stack_identifier,
+											mach_vm_address_t *stack_frames_buffer,
+											uint32_t max_stack_frames,
+											uint32_t *count,
+											bool *last_frame_is_threadid)
 {
 	remote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);
 	if (remote_fd == NULL) {
@@ -2432,6 +2517,10 @@
 	unwind_stack_from_table_index(&remote_fd->cache->uniquing_table_snapshot, stack_identifier, stack_frames_buffer, count, max_stack_frames, lite_mode);
 
 	release_file_streams_for_task(task);
+
+	if (last_frame_is_threadid) {
+		*last_frame_is_threadid = !lite_mode;
+	}
 
 	if (*count) {
 		return KERN_SUCCESS;
@@ -2559,7 +2648,7 @@
 	uint64_t num_nodes = 0;
 	while (table_chunk_header) {
 		num_nodes += table_chunk_header->num_nodes_in_chunk;
-		size_t chunk_size = 2 * sizeof(mach_vm_address_t) * table_chunk_header->num_nodes_in_chunk;
+		size_t chunk_size = 2 * sizeof(mach_vm_address_t) *  (size_t)table_chunk_header->num_nodes_in_chunk;
 		kr = mach_vm_copy(mach_task_self(), (mach_vm_address_t)table_chunk_header->table_chunk, chunk_size, (vm_address_t)p);
 		if (kr != KERN_SUCCESS) {
 			memcpy(p, table_chunk_header->table_chunk, chunk_size);