/* auto_setup: called by dynamo_auto_start for non-early follow children. * This routine itself would be dynamo_auto_start except that we want * our own go-native path separate from load_dynamo (we could still have * this by dynamo_auto_start and jump to an asm routine for go-native, * but keeping the entry in asm is more flexible). * Assumptions: The saved priv_mcontext_t for the start of the app is on * the stack, followed by a pointer to a region of memory to free * (which can be NULL) and its size. If we decide not to take over * this process, this routine returns; otherwise it does not return. */ void auto_setup(ptr_uint_t appstack) { dcontext_t *dcontext; priv_mcontext_t *mcontext; byte *pappstack; byte *addr; pappstack = (byte *)appstack; /* Our parameter points at a priv_mcontext_t struct, beyond which are * two other fields: pappstack --> +0 priv_mcontext_t struct +x addr of memory to free (can be NULL) +y sizeof memory to free */ automatic_startup = true; /* we should control all threads */ control_all_threads = true; dynamorio_app_init(); if (INTERNAL_OPTION(nullcalls)) { dynamorio_app_exit(); return; } /* For apps injected using follow_children, this is where control should be * allowed to go native for hotp_only & thin_client. */ if (RUNNING_WITHOUT_CODE_CACHE()) return; /* useful to debug fork-following */ DOLOG(4, LOG_TOP, { SYSLOG_INTERNAL_INFO("dynamo auto start"); });
/* os specific loader initialization epilogue after finalizing the load. */ void os_loader_init_epilogue(void) { #ifdef INTERNAL /* Print the add-symbol-file commands so they can be copy-pasted into gdb. * We have to do it in a single syslog so they can be copy pasted. Since * info syslogs are only in internal builds, we only do this work in an * internal build. To debug an external build, we rely on the gdb script to * find text_addr in opd. * FIXME i#531: Support attaching from the gdb script. */ privmod_t *mod; size_t sofar = 0; size_t bufsz = 4096; /* Should be enough, but too much for stack. */ char *buf; /* FIXME: Skip this work if we're not going to print or log. */ ASSERT(dynamo_heap_initialized); ASSERT(!printed_gdb_commands); buf = HEAP_ARRAY_ALLOC(GLOBAL_DCONTEXT, char, bufsz, ACCT_OTHER, PROTECTED); acquire_recursive_lock(&privload_lock); for (mod = privload_first_module(); mod != NULL; mod = privload_next_module(mod)) { os_privmod_data_t *opd = (os_privmod_data_t *) mod->os_privmod_data; /* GDB already finds externally loaded modules (e.g. DR). */ if (mod->externally_loaded) continue; print_to_buffer(buf, bufsz, &sofar, "add-symbol-file '%s' %p\n", mod->path, opd->text_addr); } printed_gdb_commands = true; release_recursive_lock(&privload_lock); if (sofar > 0) { SYSLOG_INTERNAL_INFO("Paste into GDB to debug DynamoRIO clients:\n" /* Need to turn off confirm for paste to work. */ "set confirm off\n" "%s", buf); } HEAP_ARRAY_FREE(GLOBAL_DCONTEXT, buf, char, bufsz, ACCT_OTHER, PROTECTED); #endif /* INTERNAL */ }
static #endif void handle_nudge(dcontext_t *dcontext, nudge_arg_t *arg) { uint nudge_action_mask = arg->nudge_action_mask; /* Future version checks would go here. */ ASSERT_CURIOSITY(arg->version == NUDGE_ARG_CURRENT_VERSION); /* Nudge shouldn't start with any locks held. Do this assert after the * dynamo_exited check, other wise the locks may be deleted. */ ASSERT_OWN_NO_LOCKS(); STATS_INC(num_nudges); #ifdef WINDOWS /* Linux does this in signal.c */ SYSLOG_INTERNAL_INFO("received nudge mask=0x%x id=0x%08x arg=0x"ZHEX64_FORMAT_STRING, arg->nudge_action_mask, arg->client_id, arg->client_arg); #endif if (nudge_action_mask == 0) { ASSERT_CURIOSITY(false && "Nudge: no action specified"); return; } else if (nudge_action_mask >= NUDGE_GENERIC(PARAMETRIZED_END)) { ASSERT(false && "Nudge: unknown nudge action"); return; } /* In -thin_client mode only detach and process_control nudges are allowed; * case 8888. */ #define VALID_THIN_CLIENT_NUDGES (NUDGE_GENERIC(process_control)|NUDGE_GENERIC(detach)) if (DYNAMO_OPTION(thin_client)) { if (TEST(VALID_THIN_CLIENT_NUDGES, nudge_action_mask)) { /* If it is a valid thin client nudge, then disable all others. */ nudge_action_mask &= VALID_THIN_CLIENT_NUDGES; } else { return; /* invalid nudge for thin_client, so mute it */ } } /* FIXME: NYI action handlers. As implemented move to desired order. */ if (TEST(NUDGE_GENERIC(upgrade), nudge_action_mask)) { /* FIXME: watch out for flushed clean-call fragment */ nudge_action_mask &= ~NUDGE_GENERIC(upgrade); ASSERT_NOT_IMPLEMENTED(false && "case 4179"); } if (TEST(NUDGE_GENERIC(kstats), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(kstats); ASSERT_NOT_IMPLEMENTED(false); } #ifdef INTERNAL if (TEST(NUDGE_GENERIC(stats), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(stats); ASSERT_NOT_IMPLEMENTED(false); } if (TEST(NUDGE_GENERIC(invalidate), nudge_action_mask)) { /* FIXME: watch out for flushed clean-call fragment */ nudge_action_mask &= ~NUDGE_GENERIC(invalidate); ASSERT_NOT_IMPLEMENTED(false); } if (TEST(NUDGE_GENERIC(recreate_pc), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(recreate_pc); ASSERT_NOT_IMPLEMENTED(false); } if (TEST(NUDGE_GENERIC(recreate_state), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(recreate_state); ASSERT_NOT_IMPLEMENTED(false); } if (TEST(NUDGE_GENERIC(reattach), nudge_action_mask)) { /* FIXME: watch out for flushed clean-call fragment */ nudge_action_mask &= ~NUDGE_GENERIC(reattach); ASSERT_NOT_IMPLEMENTED(false); } #endif /* INTERNAL */ if (TEST(NUDGE_GENERIC(diagnose), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(diagnose); ASSERT_NOT_IMPLEMENTED(false); } /* Implemented action handlers */ if (TEST(NUDGE_GENERIC(opt), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(opt); synchronize_dynamic_options(); } if (TEST(NUDGE_GENERIC(ldmp), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(ldmp); os_dump_core("Nudge triggered ldmp."); } if (TEST(NUDGE_GENERIC(freeze), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(freeze); coarse_units_freeze_all(true/*in-place: FIXME: separate nudge for non?*/); } if (TEST(NUDGE_GENERIC(persist), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(persist); coarse_units_freeze_all(false/*!in-place==persist*/); } #ifdef CLIENT_INTERFACE if (TEST(NUDGE_GENERIC(client), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(client); instrument_nudge(dcontext, arg->client_id, arg->client_arg); } #endif #ifdef PROCESS_CONTROL if (TEST(NUDGE_GENERIC(process_control), nudge_action_mask)) { /* Case 8594 */ nudge_action_mask &= ~NUDGE_GENERIC(process_control); /* Need to synchronize because process control can be switched between * on (white or black list) & off. FIXME - the nudge mask should specify this, * but doesn't hurt to do it again. */ synchronize_dynamic_options(); if (IS_PROCESS_CONTROL_ON()) process_control(); /* If process control is enforced then control won't come back. If * either -detect_mode is on or if there was nothing to enforce, control * comes back in which case it is safe to let remaining nudges be * processed because no core state would have been changed. */ } #endif #ifdef HOTPATCHING if (DYNAMO_OPTION(hot_patching) && DYNAMO_OPTION(liveshields) && TEST_ANY(NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats), nudge_action_mask)) { hotp_nudge_update(nudge_action_mask & (NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats))); nudge_action_mask &= ~(NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats)); } #endif #ifdef PROGRAM_SHEPHERDING if (TEST(NUDGE_GENERIC(violation), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(violation); /* Use nudge mechanism to trigger a security violation at an * arbitrary time. Note - is only useful for testing kill process attack * handling as this is not an app thread (we injected it). */ /* see bug 652 for planned improvements */ security_violation(dcontext, dcontext->next_tag, ATTACK_SIM_NUDGE_VIOLATION, OPTION_BLOCK|OPTION_REPORT); } #endif if (TEST(NUDGE_GENERIC(reset), nudge_action_mask)) { nudge_action_mask &= ~NUDGE_GENERIC(reset); if (DYNAMO_OPTION(enable_reset)) { mutex_lock(&reset_pending_lock); /* fcache_reset_all_caches_proactively() will unlock */ fcache_reset_all_caches_proactively(RESET_ALL); /* NOTE - reset is safe since we won't return to the code cache below (we * will in fact not return at all). */ } else { SYSLOG_INTERNAL_WARNING("nudge reset ignored since resets are disabled"); } } #ifdef WINDOWS /* The detach handler is last since in the common case it doesn't return. */ if (TEST(NUDGE_GENERIC(detach), nudge_action_mask)) { dcontext->free_app_stack = false; nudge_action_mask &= ~NUDGE_GENERIC(detach); detach_helper(DETACH_NORMAL_TYPE); } #endif }