Loading...
--- libmalloc/libmalloc-116/src/stack_logging_disk.c
+++ libmalloc/libmalloc-166.200.60/src/stack_logging_disk.c
@@ -22,19 +22,20 @@
*/
#include "internal.h"
+#include "radix_tree.h"
#pragma mark -
#pragma mark Defines
-#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
-// _malloc_printf(ASL_LEVEL_INFO...) on iOS doesn't show up in the Xcode Console log of the device,
+#if TARGET_OS_IPHONE
+// malloc_report(ASL_LEVEL_INFO...) on iOS doesn't show up in the Xcode Console log of the device,
// but ASL_LEVEL_NOTICE does. So raising the log level is helpful.
#undef ASL_LEVEL_INFO
#define ASL_LEVEL_INFO ASL_LEVEL_NOTICE
-#endif
+#endif // TARGET_OS_IPHONE
#ifdef TEST_DISK_STACK_LOGGING
-#define _malloc_printf fprintf
+#define malloc_report fprintf
#undef ASL_LEVEL_INFO
#define ASL_LEVEL_INFO stderr
#endif
@@ -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:
@@ -169,7 +173,7 @@
task_t remote_task;
pid_t remote_pid;
int32_t task_is_64_bit;
- boolean_t task_uses_lite_mode;
+ boolean_t task_uses_lite_or_vmlite_mode;
int32_t in_use_count;
FILE *index_file_stream;
uint64_t remote_stack_buffer_shared_memory_address;
@@ -202,7 +206,7 @@
};
} table_slot_t;
-#pragma pop
+#pragma pack(pop)
_Static_assert(sizeof(table_slot_t) == 16, "table_slot_t must be 128 bits");
@@ -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;
@@ -272,7 +277,7 @@
mach_vm_address_t allocatedMem = 0ull;
if (mach_vm_allocate(mach_task_self(), &allocatedMem, memSize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL)) !=
KERN_SUCCESS) {
- malloc_printf("allocate_pages(): virtual memory exhausted!\n");
+ malloc_report(ASL_LEVEL_ERR, "allocate_pages(): virtual memory exhausted!\n");
}
return (void *)(uintptr_t)allocatedMem;
}
@@ -287,7 +292,7 @@
static const uint64_t max_table_size_normal = UINT64_MAX;
static backtrace_uniquing_table *
-__create_uniquing_table(boolean_t lite_mode)
+__create_uniquing_table(boolean_t lite_or_vmlite_mode)
{
backtrace_uniquing_table *uniquing_table =
(backtrace_uniquing_table *)sld_allocate_pages((uint64_t)round_page(sizeof(backtrace_uniquing_table)));
@@ -302,15 +307,15 @@
uniquing_table->table_address = (uintptr_t)uniquing_table->u.table;
uniquing_table->max_collide = INITIAL_MAX_COLLIDE;
uniquing_table->untouchableNodes = 0;
- uniquing_table->max_table_size = (lite_mode) ? max_table_size_lite : max_table_size_normal;
- uniquing_table->nodes_use_refcount = lite_mode;
+ uniquing_table->max_table_size = (lite_or_vmlite_mode) ? max_table_size_lite : max_table_size_normal;
+ uniquing_table->nodes_use_refcount = lite_or_vmlite_mode;
uniquing_table->in_client_process = 0;
#if BACKTRACE_UNIQUING_DEBUG
- malloc_printf("create_uniquing_table(): creating. size: %lldKB == %lldMB, numnodes: %lld (%lld untouchable)\n",
+ malloc_report(ASL_LEVEL_INFO, "create_uniquing_table(): creating. size: %lldKB == %lldMB, numnodes: %lld (%lld untouchable)\n",
uniquing_table->tableSize >> 10, uniquing_table->tableSize >> 20, uniquing_table->numNodes,
uniquing_table->untouchableNodes);
- malloc_printf("create_uniquing_table(): table: %p; end: %p\n", uniquing_table->u.table,
+ malloc_report(ASL_LEVEL_INFO, "create_uniquing_table(): table: %p; end: %p\n", uniquing_table->u.table,
(void *)((uintptr_t)uniquing_table->u.table + (uintptr_t)uniquing_table->tableSize));
#endif
return uniquing_table;
@@ -335,7 +340,7 @@
uint64_t newsize = (uniquing_table->numPages << EXPAND_FACTOR) * vm_page_size;
if (newsize > uniquing_table->max_table_size) {
- malloc_printf("no more space in uniquing table\n");
+ malloc_report(ASL_LEVEL_ERR, "no more space in uniquing table\n");
return false;
}
@@ -350,24 +355,24 @@
if (mach_vm_copy(mach_task_self(), (mach_vm_address_t)(uintptr_t)oldTable, oldsize, (mach_vm_address_t)(uintptr_t)newTable) !=
KERN_SUCCESS) {
- malloc_printf("expandUniquingTable(): VMCopyFailed\n");
+ malloc_report(ASL_LEVEL_ERR, "expandUniquingTable(): VMCopyFailed\n");
}
uniquing_table->untouchableNodes = oldnumnodes;
#if BACKTRACE_UNIQUING_DEBUG
- malloc_printf(
+ malloc_report(ASL_LEVEL_INFO,
"expandUniquingTable(): expanded from nodes full: %lld of: %lld (~%2d%%); to nodes: %lld (inactive = %lld); unique "
"bts: %lld\n",
uniquing_table->nodesFull, oldnumnodes, (int)(((uniquing_table->nodesFull * 100.0) / (double)oldnumnodes) + 0.5),
uniquing_table->numNodes, uniquing_table->untouchableNodes, uniquing_table->backtracesContained);
- malloc_printf("expandUniquingTable(): allocate: %p; end: %p\n", newTable,
+ malloc_report(ASL_LEVEL_INFO, "expandUniquingTable(): allocate: %p; end: %p\n", newTable,
(void *)((uintptr_t)newTable + (uintptr_t)(uniquing_table->tableSize)));
- malloc_printf("expandUniquingTable(): deallocate: %p; end: %p\n", oldTable, (void *)((uintptr_t)oldTable + (uintptr_t)oldsize));
- malloc_printf("expandUniquingTable(): new size = %llu\n", newsize);
+ malloc_report(ASL_LEVEL_INFO, "expandUniquingTable(): deallocate: %p; end: %p\n", oldTable, (void *)((uintptr_t)oldTable + (uintptr_t)oldsize));
+ malloc_report(ASL_LEVEL_INFO, "expandUniquingTable(): new size = %llu\n", newsize);
#endif
if (sld_deallocate_pages(oldTable, oldsize) != KERN_SUCCESS) {
- malloc_printf("expandUniquingTable(): mach_vm_deallocate failed. [%p]\n", uniquing_table->u.table);
+ malloc_report(ASL_LEVEL_ERR, "expandUniquingTable(): mach_vm_deallocate failed. [%p]\n", uniquing_table->u.table);
}
return true;
@@ -507,7 +512,7 @@
static void
postpone_stack_logging(void)
{
- _malloc_printf(ASL_LEVEL_INFO, "stack logging postponed until after initialization.\n");
+ malloc_report(ASL_LEVEL_INFO, "stack logging postponed until after initialization.\n");
stack_logging_postponed = 1;
}
@@ -539,7 +544,7 @@
strlcpy(target, evn_log_directory, (size_t)PATH_MAX);
return true;
} else {
- _malloc_printf(ASL_LEVEL_INFO, "MallocStackLoggingDirectory env var set to unwritable path '%s'\n", evn_log_directory);
+ malloc_report(ASL_LEVEL_INFO, "MallocStackLoggingDirectory env var set to unwritable path '%s'\n", evn_log_directory);
}
}
@@ -645,14 +650,14 @@
// On first use, allocate space directly from the OS without using malloc
__stack_log_file_path__ = sld_allocate_pages((uint64_t)round_page(PATH_MAX));
if (__stack_log_file_path__ == NULL) {
- _malloc_printf(ASL_LEVEL_INFO, "unable to allocate memory for stack log file path\n");
+ malloc_report(ASL_LEVEL_INFO, "unable to allocate memory for stack log file path\n");
return NULL;
}
}
if (!get_writeable_logging_directory(__stack_log_file_path__)) {
if (!stack_logging_postponed) {
- _malloc_printf(ASL_LEVEL_INFO, "No writeable tmp dir\n");
+ malloc_report(ASL_LEVEL_INFO, "No writeable tmp dir\n");
}
return NULL;
}
@@ -689,10 +694,10 @@
// Securely create the log file.
if ((index_file_descriptor = my_mkstemps(__stack_log_file_path__, (int)strlen(stack_log_file_suffix))) != -1) {
- _malloc_printf(ASL_LEVEL_INFO, "stack logs being written into %s\n", __stack_log_file_path__);
+ malloc_report(ASL_LEVEL_INFO, "stack logs being written into %s\n", __stack_log_file_path__);
created_log_location = __stack_log_file_path__;
} else {
- _malloc_printf(ASL_LEVEL_INFO, "unable to create stack logs at %s\n", __stack_log_file_path__);
+ malloc_report(ASL_LEVEL_INFO, "unable to create stack logs at %s\n", __stack_log_file_path__);
__stack_log_file_path__[0] = '\0';
created_log_location = NULL;
}
@@ -723,10 +728,10 @@
{
if (__stack_log_file_path__ && __stack_log_file_path__[0]) {
if (delete_logging_file(__stack_log_file_path__) == 0) {
- _malloc_printf(ASL_LEVEL_INFO, "stack logs deleted from %s\n", __stack_log_file_path__);
+ malloc_report(ASL_LEVEL_INFO, "stack logs deleted from %s\n", __stack_log_file_path__);
__stack_log_file_path__[0] = '\0';
} else {
- _malloc_printf(ASL_LEVEL_INFO, "unable to delete stack logs from %s\n", __stack_log_file_path__);
+ malloc_report(ASL_LEVEL_INFO, "unable to delete stack logs from %s\n", __stack_log_file_path__);
}
}
}
@@ -767,7 +772,7 @@
// Ensure that we can access this directory - permissions or sandbox'ing might prevent it.
if (access(directory, R_OK | W_OK | X_OK) == -1 || (dp = opendir(directory)) == NULL) {
- //_malloc_printf(ASL_LEVEL_INFO, "reaping: no access to %s\n", directory);
+ //malloc_report(ASL_LEVEL_INFO, "reaping: no access to %s\n", directory);
return;
}
@@ -805,7 +810,7 @@
// OK, we found a lowest-level directory matching <remaining_path_format>, and we have access to it.
// Reap any unnecessary stack log files in here.
- //_malloc_printf(ASL_LEVEL_INFO, "reaping: looking in %s\n", directory);
+ //malloc_report(ASL_LEVEL_INFO, "reaping: looking in %s\n", directory);
// __stack_log_file_path__ may be NULL if this code is running in an analysis tool client process that is not
// itself running with MallocStackLogging set.
@@ -826,9 +831,9 @@
strlcpy(suffix, entry->d_name, (size_t)PATH_MAX - pathname_len);
if (delete_logging_file(pathname) == 0) {
if (pid == curpid) {
- _malloc_printf(ASL_LEVEL_INFO, "stack logs deleted from %s\n", pathname);
+ malloc_report(ASL_LEVEL_INFO, "stack logs deleted from %s\n", pathname);
} else {
- _malloc_printf(ASL_LEVEL_INFO, "process %ld no longer exists, stack logs deleted from %s\n", pid, pathname);
+ malloc_report(ASL_LEVEL_INFO, "process %ld no longer exists, stack logs deleted from %s\n", pid, pathname);
}
}
}
@@ -853,14 +858,14 @@
// Now reap files left over in any other accessible app-specific temp directories.
// These could be from sandbox'ed apps.
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
char *root_of_temp_directories = "/private/var/mobile/Containers/Data/Application"; // ugh - hard-coding to user name "mobile".
// Works for all iOS's up to now.
char *temp_directories_path_format = "<application-UUID>/tmp";
-#else
+#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
char *root_of_temp_directories = "/private/var/folders";
char *temp_directories_path_format = "<xx>/<random>/T";
-#endif
+#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
reap_orphaned_log_files_in_hierarchy(root_of_temp_directories, temp_directories_path_format, target_pid, streams);
}
@@ -871,7 +876,7 @@
static void
disable_stack_logging(void)
{
- _malloc_printf(ASL_LEVEL_INFO, "stack logging disabled due to previous errors.\n");
+ malloc_report(ASL_LEVEL_INFO, "stack logging disabled due to previous errors.\n");
stack_logging_enable_logging = 0;
malloc_logger = NULL;
__syscall_logger = NULL;
@@ -920,7 +925,7 @@
fd_to_reset = &index_file_descriptor;
} else {
// We don't know about this file. Return (and abort()).
- _malloc_printf(ASL_LEVEL_INFO, "Unknown file descriptor; expecting stack logging index file\n");
+ malloc_report(ASL_LEVEL_INFO, "Unknown file descriptor; expecting stack logging index file\n");
return -1;
}
@@ -932,7 +937,7 @@
int fds_to_close[3] = {0};
while (fd < 3) {
if (fd == -1) {
- _malloc_printf(ASL_LEVEL_INFO, "unable to re-open stack logging file %s\n", file_to_reopen);
+ malloc_report(ASL_LEVEL_INFO, "unable to re-open stack logging file %s\n", file_to_reopen);
delete_log_files();
return -1;
}
@@ -977,7 +982,7 @@
while (remaining > 0) {
written = robust_write(index_file_descriptor, p, remaining);
if (written == -1) {
- _malloc_printf(
+ malloc_report(
ASL_LEVEL_INFO, "Unable to write to stack logging file %s (%s)\n", __stack_log_file_path__, strerror(errno));
disable_stack_logging();
return;
@@ -991,7 +996,7 @@
}
__attribute__((visibility("hidden"))) boolean_t
-__prepare_to_log_stacks(boolean_t lite_mode)
+__prepare_to_log_stacks(boolean_t lite_or_vmlite_mode)
{
if (!pre_write_buffers) {
last_logged_malloc_address = 0ul;
@@ -1010,7 +1015,7 @@
pre_write_buffers = mmap(
0, full_shared_mem_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL), 0);
if (MAP_FAILED == pre_write_buffers) {
- _malloc_printf(ASL_LEVEL_INFO, "error creating VM region for stack logging output buffers\n");
+ malloc_report(ASL_LEVEL_INFO, "error creating VM region for stack logging output buffers\n");
disable_stack_logging();
return false;
}
@@ -1020,23 +1025,25 @@
pre_write_buffers->next_free_index_buffer_offset = 0;
// create the backtrace uniquing table
- pre_write_buffers->uniquing_table = __create_uniquing_table(lite_mode);
+ pre_write_buffers->uniquing_table = __create_uniquing_table(lite_or_vmlite_mode);
if (!pre_write_buffers->uniquing_table) {
- _malloc_printf(ASL_LEVEL_INFO, "error while allocating stack uniquing table\n");
+ malloc_report(ASL_LEVEL_INFO, "error while allocating stack uniquing table\n");
disable_stack_logging();
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) {
- _malloc_printf(ASL_LEVEL_INFO, "error while allocating stack trace buffer\n");
+ malloc_report(ASL_LEVEL_INFO, "error while allocating stack trace buffer\n");
disable_stack_logging();
return false;
}
// lite_mode doesn't use a file
- if (lite_mode) {
+ if (lite_or_vmlite_mode) {
__mach_stack_logging_shared_memory_address = (uint64_t) pre_write_buffers;
} else {
// this call ensures that the log files exist; analyzing processes will rely on this assumption.
@@ -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().
@@ -1191,7 +1200,7 @@
do {
if (parent == prev_parent) {
- malloc_printf("circular parent reference in __decrement_table_slot_refcount\n");
+ malloc_report(ASL_LEVEL_ERR, "circular parent reference in __decrement_table_slot_refcount\n");
break;
}
@@ -1217,6 +1226,13 @@
if (!stack_logging_enable_logging || stack_logging_postponed) {
return;
}
+
+ bool stack_logging_mode_lite_or_vmlite = stack_logging_mode == stack_logging_mode_lite || stack_logging_mode == stack_logging_mode_vmlite;
+
+ if (stack_logging_mode_lite_or_vmlite &&
+ !((type_flags & stack_logging_type_vm_allocate) || (type_flags & stack_logging_type_vm_deallocate))) {
+ return;
+ }
uintptr_t size;
uintptr_t ptr_arg;
@@ -1225,9 +1241,6 @@
if (type_flags & stack_logging_type_alloc && type_flags & stack_logging_type_dealloc) {
size = arg3;
ptr_arg = arg2; // the original pointer
- if (ptr_arg == return_val) {
- return; // realloc had no effect, skipping
- }
if (ptr_arg == 0) { // realloc(NULL, size) same as malloc(size)
type_flags ^= stack_logging_type_dealloc;
} else {
@@ -1252,7 +1265,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 +1282,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 +1297,21 @@
thread_doing_logging = self_thread; // for preventing deadlock'ing on stack logging on a single thread
+ if (stack_logging_mode_lite_or_vmlite && (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 +1326,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_lite_or_vmlite) {
+ 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_lite_or_vmlite && (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;
@@ -1337,7 +1372,7 @@
current_index.offset_and_flags = STACK_LOGGING_OFFSET_AND_FLAGS(uniqueStackIdentifier, type_flags);
// the following line is a good debugging tool for logging each allocation event as it happens.
- // malloc_printf("{0x%lx, %lld}\n", STACK_LOGGING_DISGUISE(current_index.address), uniqueStackIdentifier);
+ // malloc_report(ASL_LEVEL_INFO, "{0x%lx, %lld}\n", STACK_LOGGING_DISGUISE(current_index.address), uniqueStackIdentifier);
// flush the data buffer to disk if necessary
if (pre_write_buffers->next_free_index_buffer_offset + sizeof(stack_logging_index_event) >= STACK_LOGGING_BLOCK_WRITING_SIZE) {
@@ -1349,6 +1384,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);
}
@@ -1655,16 +1691,16 @@
static mach_vm_address_t
map_shared_memory_from_task(task_t sourceTask, mach_vm_address_t sourceAddress, mach_vm_size_t sourceSize)
{
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
int mapRequestFlags = VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR;
mach_vm_address_t mapRequestAddress = sourceAddress;
mach_vm_size_t mapRequestSize = sourceSize;
-#else
+#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
// Sadly, VM_FLAGS_RETURN_DATA_ADDR isn't available to us; align everything manually.
int mapRequestFlags = VM_FLAGS_ANYWHERE;
mach_vm_address_t mapRequestAddress = trunc_page(sourceAddress);
mach_vm_size_t mapRequestSize = round_page(sourceAddress + sourceSize) - mapRequestAddress;
-#endif
+#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
mach_vm_address_t mappedAddress = 0;
vm_prot_t outCurrentProt = VM_PROT_NONE;
vm_prot_t outMaxProt = VM_PROT_NONE;
@@ -1694,11 +1730,21 @@
descriptors->remote_stack_buffer_shared_memory_address, sizeof(stack_buffer_shared_memory));
if (!cache->shmem) {
// failed to connect to the shared memory region; warn and continue.
- _malloc_printf(ASL_LEVEL_INFO,
+ malloc_report(ASL_LEVEL_INFO,
"warning: unable to map shared memory from %llx in target process %d; no stack backtraces will be available.\n",
descriptors->remote_stack_buffer_shared_memory_address, descriptors->remote_pid);
}
- cache->lite_mode = descriptors->task_uses_lite_mode;
+ cache->lite_mode = descriptors->task_uses_lite_or_vmlite_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_report(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
@@ -1744,7 +1790,7 @@
}
// need to update the snapshot if in lite mode and haven't yet read the uniquing table
- if (descriptors->task_uses_lite_mode && cache->uniquing_table_snapshot.numPages == 0) {
+ if (descriptors->task_uses_lite_or_vmlite_mode && cache->uniquing_table_snapshot.numPages == 0) {
update_snapshot = true;
}
@@ -2025,7 +2071,7 @@
if (strncmp(p, env_var_name, env_var_name_length) == 0 && p[env_var_name_length] == '=') {
p += env_var_name_length + 1;
strlcpy(env_var_value_buf, p, buf_length);
- //_malloc_printf(ASL_LEVEL_INFO, "found env var %s='%s'\n", env_var_name, env_var_value_buf);
+ //malloc_report(ASL_LEVEL_INFO, "found env var %s='%s'\n", env_var_name, env_var_value_buf);
return true;
}
while (p < endp && *p != '\0')
@@ -2117,7 +2163,7 @@
if (shared_memory_address != 0) {
this_task_streams->remote_stack_buffer_shared_memory_address = shared_memory_address;
- this_task_streams->task_uses_lite_mode = true;
+ this_task_streams->task_uses_lite_or_vmlite_mode = true;
} else {
open_log_file(pid, this_task_streams);
@@ -2178,7 +2224,7 @@
return KERN_FAILURE;
}
- *uses_lite_mode = remote_fd->task_uses_lite_mode;
+ *uses_lite_mode = remote_fd->task_uses_lite_or_vmlite_mode;
return KERN_SUCCESS;
}
@@ -2200,7 +2246,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 +2359,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 +2456,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 +2516,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 +2647,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);