+ uniquing_table->table = newTable;
+ uniquing_table->table_address = (uintptr_t)uniquing_table->table;
+ uniquing_table->max_collide = uniquing_table->max_collide + COLLISION_GROWTH_RATE;
+
+ 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");
+ }
+ uniquing_table->untouchableNodes = oldnumnodes;
+
+#if BACKTRACE_UNIQUING_DEBUG
+ malloc_printf("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, (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));
+#endif
+
+ if (deallocate_pages(oldTable, oldsize) != KERN_SUCCESS) {
+ malloc_printf("expandUniquingTable(): mach_vm_deallocate failed. [%p]\n", uniquing_table->table);
+ }
+}
+
+static int
+__enter_frames_in_table(backtrace_uniquing_table *uniquing_table, uint64_t *foundIndex, mach_vm_address_t *frames, int32_t count)
+{
+ // The hash values need to be the same size as the addresses (because we use the value -1), for clarity, define a new type
+ typedef mach_vm_address_t hash_index_t;
+
+ mach_vm_address_t thisPC;
+ hash_index_t hash, uParent = (hash_index_t)(-1ll), modulus = (uniquing_table->numNodes-uniquing_table->untouchableNodes-1);
+ int32_t collisions, lcopy = count, returnVal = 1;
+ hash_index_t hash_multiplier = ((uniquing_table->numNodes - uniquing_table->untouchableNodes)/(uniquing_table->max_collide*2+1));
+ mach_vm_address_t *node;
+ while (--lcopy >= 0) {
+ thisPC = frames[lcopy];
+
+ // hash = initialHash(uniquing_table, uParent, thisPC);
+ hash = uniquing_table->untouchableNodes + (((uParent << 4) ^ (thisPC >> 2)) % modulus);
+ collisions = uniquing_table->max_collide;
+
+ while (collisions--) {
+ node = uniquing_table->table + (hash * 2);
+
+ if (*node == 0 && node[1] == 0) {
+ // blank; store this entry!
+ // Note that we need to test for both head[0] and head[1] as (0, -1) is a valid entry
+ node[0] = thisPC;
+ node[1] = uParent;
+ uParent = hash;
+#if BACKTRACE_UNIQUING_DEBUG
+ uniquing_table->nodesFull++;
+ if (lcopy == 0) {
+ uniquing_table->backtracesContained++;
+ }
+#endif
+ break;
+ }
+ if (*node == thisPC && node[1] == uParent) {
+ // hit! retrieve index and go.
+ uParent = hash;
+ break;
+ }
+
+ hash += collisions * hash_multiplier + 1;
+
+ if (hash >= uniquing_table->numNodes) {
+ hash -= (uniquing_table->numNodes - uniquing_table->untouchableNodes); // wrap around.
+ }
+ }
+
+ if (collisions < 0) {
+ returnVal = 0;
+ break;
+ }
+ }
+
+ if (returnVal) *foundIndex = uParent;
+
+ return returnVal;
+}
+
+static void
+__unwind_stack_from_table_index(backtrace_uniquing_table *uniquing_table, uint64_t index_pos, mach_vm_address_t *out_frames_buffer, uint32_t *out_frames_count, uint32_t max_frames)
+{
+ mach_vm_address_t *node = uniquing_table->table + (index_pos * 2);
+ uint32_t foundFrames = 0;
+ if (index_pos < uniquing_table->numNodes) {
+ while (foundFrames < max_frames) {
+ out_frames_buffer[foundFrames++] = node[0];
+ if (node[1] == (mach_vm_address_t)(-1ll)) break;
+ node = uniquing_table->table + (node[1] * 2);
+ }
+ }
+
+ *out_frames_count = foundFrames;
+}
+
+#pragma mark -
+#pragma mark Disk Stack Logging
+
+static void delete_log_files(void); // pre-declare
+static int delete_logging_file(char *log_location);
+
+static void
+append_int(char * filename, pid_t pid, size_t maxLength)
+{
+ size_t len = strlen(filename);
+
+ uint32_t count = 0;
+ pid_t value = pid;