Пример #1
0
/*
 * Perform some operations at the "top" of the interpreter loop.
 * This stuff is required to support debugging and profiling.
 *
 * Using" __attribute__((noinline))" seems to do more harm than good.  This
 * is best when inlined due to the large number of parameters, most of
 * which are local vars in the main interp loop.
 */
static void checkDebugAndProf(const u2* pc, const u4* fp, Thread* self,
    const Method* method, bool* pIsMethodEntry)
{
    /* check to see if we've run off end of method */
    assert(pc >= method->insns && pc <
            method->insns + dvmGetMethodInsnsSize(method));

#if 0
    /*
     * When we hit a specific method, enable verbose instruction logging.
     * Sometimes it's helpful to use the debugger attach as a trigger too.
     */
    if (*pIsMethodEntry) {
        static const char* cd = "Landroid/test/Arithmetic;";
        static const char* mn = "shiftTest2";
        static const char* sg = "()V";

        if (/*gDvm.debuggerActive &&*/
            strcmp(method->clazz->descriptor, cd) == 0 &&
            strcmp(method->name, mn) == 0 &&
            strcmp(method->shorty, sg) == 0)
        {
            LOGW("Reached %s.%s, enabling verbose mode\n",
                method->clazz->descriptor, method->name);
            android_setMinPriority(LOG_TAG"i", ANDROID_LOG_VERBOSE);
            dumpRegs(method, fp, true);
        }

        if (!gDvm.debuggerActive)
            *pIsMethodEntry = false;
    }
#endif

    /*
     * If the debugger is attached, check for events.  If the profiler is
     * enabled, update that too.
     *
     * This code is executed for every instruction we interpret, so for
     * performance we use a couple of #ifdef blocks instead of runtime tests.
     */
#ifdef WITH_PROFILER
    /* profiler and probably debugger */
    bool isEntry = *pIsMethodEntry;
    if (isEntry) {
        *pIsMethodEntry = false;
        TRACE_METHOD_ENTER(self, method);
    }
    if (gDvm.debuggerActive) {
        updateDebugger(method, pc, fp, isEntry, self);
    }
    if (gDvm.instructionCountEnableCount != 0) {
        /*
         * Count up the #of executed instructions.  This isn't synchronized
         * for thread-safety; if we need that we should make this
         * thread-local and merge counts into the global area when threads
         * exit (perhaps suspending all other threads GC-style and pulling
         * the data out of them).
         */
        int inst = *pc & 0xff;
        gDvm.executedInstrCounts[inst]++;
    }
#else
    /* debugger only */
    if (gDvm.debuggerActive) {
        bool isEntry = *pIsMethodEntry;
        updateDebugger(method, pc, fp, isEntry, self);
        if (isEntry)
            *pIsMethodEntry = false;
    }
#endif
}
Пример #2
0
/*
 * Initialize JDWP.
 *
 * Does not return until JDWP thread is running, but may return before
 * the thread is accepting network connections.
 */
JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
{
    JdwpState* state = NULL;

    /* comment this out when debugging JDWP itself */
    android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);

    state = (JdwpState*) calloc(1, sizeof(JdwpState));

    state->params = *pParams;

    state->requestSerial = 0x10000000;
    state->eventSerial = 0x20000000;
    dvmDbgInitMutex(&state->threadStartLock);
    dvmDbgInitMutex(&state->attachLock);
    dvmDbgInitMutex(&state->serialLock);
    dvmDbgInitMutex(&state->eventLock);
    state->eventThreadId = 0;
    dvmDbgInitMutex(&state->eventThreadLock);
    dvmDbgInitCond(&state->threadStartCond);
    dvmDbgInitCond(&state->attachCond);
    dvmDbgInitCond(&state->eventThreadCond);

    switch (pParams->transport) {
    case kJdwpTransportSocket:
        // LOGD("prepping for JDWP over TCP\n");
        state->transport = dvmJdwpSocketTransport();
        break;
    case kJdwpTransportAndroidAdb:
        // LOGD("prepping for JDWP over ADB\n");
        state->transport = dvmJdwpAndroidAdbTransport();
        /* TODO */
        break;
    default:
        LOGE("Unknown transport %d\n", pParams->transport);
        assert(false);
        goto fail;
    }

    if (!dvmJdwpNetStartup(state, pParams))
        goto fail;

    /*
     * Grab a mutex or two before starting the thread.  This ensures they
     * won't signal the cond var before we're waiting.
     */
    dvmDbgLockMutex(&state->threadStartLock);
    if (pParams->suspend)
        dvmDbgLockMutex(&state->attachLock);

    /*
     * We have bound to a port, or are trying to connect outbound to a
     * debugger.  Create the JDWP thread and let it continue the mission.
     */
    if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
            jdwpThreadStart, state))
    {
        /* state is getting tossed, but unlock these anyway for cleanliness */
        dvmDbgUnlockMutex(&state->threadStartLock);
        if (pParams->suspend)
            dvmDbgUnlockMutex(&state->attachLock);
        goto fail;
    }

    /*
     * Wait until the thread finishes basic initialization.
     * TODO: cond vars should be waited upon in a loop
     */
    dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
    dvmDbgUnlockMutex(&state->threadStartLock);


    /*
     * For suspend=y, wait for the debugger to connect to us or for us to
     * connect to the debugger.
     *
     * The JDWP thread will signal us when it connects successfully or
     * times out (for timeout=xxx), so we have to check to see what happened
     * when we wake up.
     */
    if (pParams->suspend) {
        dvmChangeStatus(NULL, THREAD_VMWAIT);
        dvmDbgCondWait(&state->attachCond, &state->attachLock);
        dvmDbgUnlockMutex(&state->attachLock);
        dvmChangeStatus(NULL, THREAD_RUNNING);

        if (!dvmJdwpIsActive(state)) {
            LOGE("JDWP connection failed\n");
            goto fail;
        }

        LOGI("JDWP connected\n");

        /*
         * Ordinarily we would pause briefly to allow the debugger to set
         * breakpoints and so on, but for "suspend=y" the VM init code will
         * pause the VM when it sends the VM_START message.
         */
    }

    return state;

fail:
    dvmJdwpShutdown(state);     // frees state
    return NULL;
}