PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack();
    for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
        if (!stackTrace[i].callee && frames.size())
            break;

        String functionName = stackTrace[i].friendlyFunctionName(exec);
        unsigned line;
        unsigned column;
        stackTrace[i].computeLineAndColumn(line, column);
        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, line, column));
    }

    // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
    // Fallback to getting at least the line and sourceURL from the exception if it has values and the exceptionStack doesn't.
    if (frames.size() > 0) {
        const ScriptCallFrame& firstCallFrame = frames.first();
        JSObject* exceptionObject = exception.toObject(exec);
        if (exception.isObject() && firstCallFrame.sourceURL().isEmpty()) {
            JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line"));
            int lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0;
            JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL"));
            String exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined");
            frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, lineNumber, 0);
        }
    }

    return ScriptCallStack::create(frames);
}
void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* callStack)
{
#if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
    static const int framesToShow = 31;
    static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException.

    void* samples[framesToShow + framesToSkip];
    int frames = framesToShow + framesToSkip;
    WTFGetBacktrace(samples, &frames);

    void** stack = samples + framesToSkip;
    int size = frames - framesToSkip;
    for (int i = 0; i < size; ++i) {
        const char* mangledName = nullptr;
        char* cxaDemangled = nullptr;
        Dl_info info;
        if (dladdr(stack[i], &info) && info.dli_sname)
            mangledName = info.dli_sname;
        if (mangledName)
            cxaDemangled = abi::__cxa_demangle(mangledName, nullptr, nullptr, nullptr);
        if (mangledName || cxaDemangled)
            callStack->append(ScriptCallFrame(cxaDemangled ? cxaDemangled : mangledName, ASCIILiteral("[native code]"), 0, 0));
        else
            callStack->append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), 0, 0));
        free(cxaDemangled);
    }
#else
    UNUSED_PARAM(callStack);
#endif
}
示例#3
0
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    CallFrame* callFrame = exec;
    while (true) {
        ASSERT(callFrame);
        int signedLineNumber;
        intptr_t sourceID;
        String urlString;
        JSValue function;

        exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
        String functionName;
        if (function)
            functionName = jsCast<JSFunction*>(function)->name(exec);
        else {
            // Caller is unknown, but if frames is empty we should still add the frame, because
            // something called us, and gave us arguments.
            if (!frames.isEmpty())
                break;
        }
        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
        frames.append(ScriptCallFrame(functionName, urlString, lineNumber));
        if (!function || frames.size() == maxStackSize)
            break;
        callFrame = callFrame->callerFrame();
    }
    return ScriptCallStack::create(frames);
}
示例#4
0
PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;
    if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
        Vector<StackFrame> stackTrace;
        Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
        for (size_t i = 0; i < stackTrace.size(); i++)
            frames.append(ScriptCallFrame(stackTrace[i].friendlyFunctionName(exec), stackTrace[i].friendlySourceURL(), stackTrace[i].line(), stackTrace[i].column()));
    }
    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame("undefined", "undefined", 0, 0));
    }
    return ScriptCallStack::create(frames);
}
PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;
    if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
        CallFrame* frame = exec->vm().topCallFrame;
        for (StackIterator iter = frame->begin(); iter != frame->end() && maxStackSize--; ++iter) {
            unsigned line;
            unsigned column;
            iter->computeLineAndColumn(line, column);
            frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
        }
    }
    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame("undefined", "undefined", 0, 0));
    }
    return ScriptCallStack::create(frames);
}
示例#6
0
PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;
    if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
        Vector<StackFrame> stackTrace;
        Interpreter::getStackTrace(&exec->globalData(), stackTrace);
        for (Vector<StackFrame>::const_iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
            frames.append(ScriptCallFrame(iter->friendlyFunctionName(exec), iter->friendlySourceURL(), iter->friendlyLineNumber()));
            if (frames.size() >= maxStackSize)
                break;
        }
    }
    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame("undefined", "undefined", 0));
    }
    return ScriptCallStack::create(frames);
}
Ref<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::Exception* exception, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    auto& stackTrace = exception->stack();
    VM& vm = exec->vm();
    for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
        unsigned line;
        unsigned column;
        stackTrace[i].computeLineAndColumn(line, column);
        String functionName = stackTrace[i].functionName(vm);
        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL(), static_cast<SourceID>(stackTrace[i].sourceID()), line, column));
    }

    // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't.
    if (exception->value().isObject()) {
        JSObject* exceptionObject = exception->value().toObject(exec);
        ASSERT(exceptionObject);
        int lineNumber;
        int columnNumber;
        String exceptionSourceURL;
        if (!frames.size()) {
            if (extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL))
                frames.append(ScriptCallFrame(String(), exceptionSourceURL, noSourceID, lineNumber, columnNumber));
        } else {
            // FIXME: The typical stack trace will have a native frame at the top, and consumers of
            // this code already know this (see JSDOMExceptionHandling.cpp's reportException, for
            // example - it uses firstNonNativeCallFrame). This looks like it splats something else
            // over it. That something else is probably already at stackTrace[1].
            // https://bugs.webkit.org/show_bug.cgi?id=176663
            if (!stackTrace[0].hasLineAndColumnInfo() || stackTrace[0].sourceURL().isEmpty()) {
                const ScriptCallFrame& firstCallFrame = frames.first();
                if (extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL))
                    frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, stackTrace[0].sourceID(), lineNumber, columnNumber);
            }
        }
    }

    return ScriptCallStack::create(frames);
}
ScriptCallStack::ScriptCallStack(ExecState* exec, unsigned skipArgumentCount)
    : m_initialized(false)
    , m_exec(exec)
    , m_caller(0)
{
    int signedLineNumber;
    intptr_t sourceID;
    UString urlString;
    JSValue function;

    exec->interpreter()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, function);

    unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;

    if (function) {
        m_caller = asFunction(function);
        m_frames.append(ScriptCallFrame(m_caller->name(m_exec), urlString, lineNumber, m_exec, skipArgumentCount));
    } else {
        // Caller is unknown, but we should still add the frame, because
        // something called us, and gave us arguments.
        m_frames.append(ScriptCallFrame(UString(), urlString, lineNumber, m_exec, skipArgumentCount));
    }
}
示例#9
0
void ScriptCallStack::initialize()
{
    if (!m_caller || m_initialized)
        return;

    JSValue func = m_exec->interpreter()->retrieveCaller(m_exec, m_caller);
    while (!func.isNull()) {
        InternalFunction* internalFunction = asInternalFunction(func);
        ArgList emptyArgList;
        m_frames.append(ScriptCallFrame(internalFunction->name(m_exec), UString(), 0, emptyArgList, 0));
        func = m_exec->interpreter()->retrieveCaller(m_exec, internalFunction);
    }
    m_initialized = true;
}
void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack& callStack)
{
#if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
    static const int framesToShow = 31;
    static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException.

    void* samples[framesToShow + framesToSkip];
    int frames = framesToShow + framesToSkip;
    WTFGetBacktrace(samples, &frames);

    void** stack = samples + framesToSkip;
    int size = frames - framesToSkip;
    for (int i = 0; i < size; ++i) {
        auto demangled = StackTrace::demangle(stack[i]);
        if (demangled)
            callStack.append(ScriptCallFrame(demangled->demangledName() ? demangled->demangledName() : demangled->mangledName(), ASCIILiteral("[native code]"), noSourceID, 0, 0));
        else
            callStack.append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), noSourceID, 0, 0));
    }
#else
    UNUSED_PARAM(callStack);
#endif
}
示例#11
0
static ScriptCallFrame toScriptCallFrame(v8::Handle<v8::StackFrame> frame)
{
    String sourceName;
    v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL());
    if (!sourceNameValue.IsEmpty())
        sourceName = toWebCoreString(sourceNameValue);

    String functionName;
    v8::Local<v8::String> functionNameValue(frame->GetFunctionName());
    if (!functionNameValue.IsEmpty())
        functionName = toWebCoreString(functionNameValue);

    int sourceLineNumber = frame->GetLineNumber();
    int sourceColumn = frame->GetColumn();
    return ScriptCallFrame(functionName, sourceName, sourceLineNumber, sourceColumn);
}
示例#12
0
static void toScriptCallFramesVector(v8::Handle<v8::StackTrace> stackTrace, Vector<ScriptCallFrame>& scriptCallFrames, size_t maxStackSize, bool emptyStackIsAllowed, v8::Isolate* isolate)
{
    ASSERT(isolate->InContext());
    int frameCount = stackTrace->GetFrameCount();
    if (frameCount > static_cast<int>(maxStackSize))
        frameCount = maxStackSize;
    for (int i = 0; i < frameCount; i++) {
        v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i);
        scriptCallFrames.append(toScriptCallFrame(stackFrame));
    }
    if (!frameCount && !emptyStackIsAllowed) {
        // Successfully grabbed stack trace, but there are no frames. It may happen in case
        // when a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        scriptCallFrames.append(ScriptCallFrame());
    }
}
示例#13
0
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    Vector<StackFrame> stackTrace;
    Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize + 1);
    for (size_t i = stackTrace.size() == 1 ? 0 : 1; i < stackTrace.size(); i++) {
        // This early exit is necessary to maintain our old behaviour
        // but the stack trace we produce now is complete and handles all
        // ways in which code may be running
        if (!stackTrace[i].callee && frames.size())
            break;

        String functionName = stackTrace[i].friendlyFunctionName(exec);
        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, stackTrace[i].line(), stackTrace[i].column()));
    }

    return ScriptCallStack::create(frames);
}
示例#14
0
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize, bool emptyIsAllowed)
{
    Vector<ScriptCallFrame> frames;

    if (exec) {
        CallFrame* frame = exec->vm().topCallFrame;
        CreateScriptCallStackFunctor functor(false, frames, maxStackSize);
        frame->iterate(functor);
    }

    if (frames.isEmpty() && !emptyIsAllowed) {
        // No frames found. It may happen in the case where
        // a bound function is called from native code for example.
        // Fallback to setting lineNumber to 0, and source and function name to "undefined".
        frames.append(ScriptCallFrame(ASCIILiteral("undefined"), ASCIILiteral("undefined"), 0, 0));
    }

    return ScriptCallStack::create(frames);
}
示例#15
0
    StackVisitor::Status operator()(StackVisitor& visitor)
    {
        if (m_needToSkipAFrame) {
            m_needToSkipAFrame = false;
            return StackVisitor::Continue;
        }

        if (m_remainingCapacityForFrameCapture) {
            unsigned line;
            unsigned column;
            visitor->computeLineAndColumn(line, column);
            m_frames.append(ScriptCallFrame(visitor->functionName(), visitor->sourceURL(), line, column));

            m_remainingCapacityForFrameCapture--;
            return StackVisitor::Continue;
        }

        return StackVisitor::Done;
    }
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    ASSERT(exec);
    CallFrame* frame = exec->vm().topCallFrame;
    StackIterator iter = frame->begin();
    if (iter.numberOfFrames() > 1)
        ++iter;
    for (; iter != frame->end() && maxStackSize--; ++iter) {
        // This early exit is necessary to maintain our old behaviour
        // but the stack trace we produce now is complete and handles all
        // ways in which code may be running
        if (!iter->callee() && frames.size())
            break;
        unsigned line;
        unsigned column;
        iter->computeLineAndColumn(line, column);
        frames.append(ScriptCallFrame(iter->functionName(), iter->sourceURL(), line, column));
    }
    return ScriptCallStack::create(frames);
}
示例#17
0
static ScriptCallFrame toScriptCallFrame(v8::Handle<v8::StackFrame> frame)
{
    StringBuilder stringBuilder;
    stringBuilder.appendNumber(frame->GetScriptId());
    String scriptId = stringBuilder.toString();
    String sourceName;
    v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL());
    if (!sourceNameValue.IsEmpty()) {
        int length = sourceNameValue->Length();
        sourceName = StringTraits<String>::fromV8String<V8StringOneByteTrait>(sourceNameValue, length);
    }

    String functionName;
    v8::Local<v8::String> functionNameValue(frame->GetFunctionName());
    if (!functionNameValue.IsEmpty())
        functionName = toCoreString(functionNameValue);

    int sourceLineNumber = frame->GetLineNumber();
    int sourceColumn = frame->GetColumn();
    return ScriptCallFrame(functionName, scriptId, sourceName, sourceLineNumber, sourceColumn);
}
void ScriptCallStack::initialize()
{
    if (!m_caller || m_initialized)
        return;

    int signedLineNumber;
    intptr_t sourceID;
    UString urlString;
    JSValue function;
    // callFrame must exist if m_caller is not null.
    CallFrame* callFrame = m_exec->callerFrame();
    while (true) {
        ASSERT(callFrame);
        m_exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
        if (!function)
            break;
        JSFunction* jsFunction = asFunction(function);
        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
        m_frames.append(ScriptCallFrame(jsFunction->name(m_exec), urlString, lineNumber, m_exec, 0));
        callFrame = callFrame->callerFrame();
    }
    m_initialized = true;
}