Package org.jnode.vm

Source Code of org.jnode.vm.VmStackReader

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm;

import org.jnode.annotation.Internal;
import org.jnode.annotation.KernelSpace;
import org.jnode.annotation.MagicPermission;
import org.jnode.vm.classmgr.VmCompiledCode;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.objects.VmSystemObject;
import org.jnode.vm.scheduler.VmThread;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;

/**
* Abstract class for reading information from stack frames.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
public abstract class VmStackReader extends VmSystemObject {

    /**
     * Gets the previous frame (if any)
     *
     * @param sf The stackframe to get the previous frame from.
     * @return The previous frame or null.
     */
    @KernelSpace
    @Internal
    public final Address getPrevious(Address sf) {
        if (isValid(sf)) {
            return sf.loadAddress(getPreviousOffset(sf));
        } else {
            return null;
        }
    }

    /**
     * Gets the method of a given stackframe.
     *
     * @param sf Stackframe pointer
     * @return The method
     */
    @KernelSpace
    final VmMethod getMethod(Address sf) {
        final int ccid = sf.loadInt(getMethodIdOffset(sf));
        if (ccid == 0) {
            return null;
        } else {
            final VmCompiledCode cc = VmUtils.getVm().getCompiledMethods().get(ccid);
            if (cc == null) {
                // (This can happen if an exception is thrown while a frame
                // for a 'native' method call is on the stack.  A panic is not a
                // good idea.  It is better to generate a stack trace with a missing
                // method name.)
               
                // Unsafe.die("Unknown ccid found on stack");
                return null;
            } else {
                return cc.getMethod();
            }
        }
    }

    /**
     * Gets the compiled code of a given stackframe.
     *
     * @param sf Stackframe pointer
     * @return The compiled code
     */
    final VmCompiledCode getCompiledCode(Address sf) {
        final int ccid = sf.loadInt(getMethodIdOffset(sf));
        if (ccid == 0) {
            return null;
        } else {
            return VmUtils.getVm().getCompiledMethods().get(ccid);
        }
    }

    /**
     * Gets the return address of a given stackframe.
     *
     * @param sf Stackframe pointer
     * @return The address
     */
    @Internal
    public final Address getReturnAddress(Address sf) {
        return sf.loadAddress(getReturnAddressOffset(sf));
    }

    /**
     * Is a given stackframe valid?
     *
     * @param sf
     * @return boolean
     */
    @KernelSpace
    final boolean isValid(Address sf) {
        if (sf == null) {
            return false;
        }
        if (getMethod(sf) == null) {
            return false;
        }
        return true;
    }

    /**
     * Is the given frame a bottom of stack marker?
     *
     * @param sf
     * @return boolean
     */
    final boolean isStackBottom(Address sf) {
        if (sf == null) {
            return true;
        }
        return (getMethod(sf) == null)
            && (getPrevious(sf) == null);
    }

    /**
     * Gets the stacktrace for a given current frame.
     *
     * @param frame    The address of the current frame.
     * @param ip       The instruction pointer of the given frame
     * @param limit    Maximum length of returned array.
     * @return VmStackFrame[]
     */
    @Internal
    public final VmStackFrame[] getVmStackTrace(Address frame, Address ip, int limit) {

        final VmStackFrameEnumerator sfEnum = new VmStackFrameEnumerator(this, frame, ip);
        int count = 0;
        while (sfEnum.isValid() && (count < limit)) {
            count++;
            sfEnum.next();
        }
//      if ((f != null) && !isStackBottom(f) && (count < limit)) {
//          Unsafe.debug("Corrupted stack!, st.length=");
//          Unsafe.debug(count);
//          Unsafe.debug(" f.magic=");
//          //Unsafe.die();
//      }

        final VmStackFrame[] stack = new VmStackFrame[count];
        sfEnum.reset(frame, ip);
        for (int i = 0; i < count; i++) {
            stack[i] = new VmStackFrame(sfEnum.getMethod(), sfEnum.getProgramCounter());
            sfEnum.next();
        }

        return stack;
    }

    /**
     * Count the number of stackframe from a given frame.
     *
     * @param sf
     * @return int
     */
    @Internal
    public final int countStackFrames(Address sf) {
        int count = 0;
        while (isValid(sf)) {
            count++;
            sf = getPrevious(sf);
        }
        return count;
    }

    /**
     * Show the current stacktrace using Screen.debug.
     */
    @KernelSpace
    public final void debugStackTrace() {
        debugStackTrace(25);
    }

    /**
     * Show the current stacktrace using Screen.debug.
     */
    @KernelSpace
    public final void debugStackTrace(int max) {
        Address f = VmMagic.getCurrentFrame();
        Unsafe.debug("\nDebug stacktrace: ");
        boolean first = true;
        while (isValid(f) && (max > 0)) {
            if (first) {
                first = false;
            } else {
                Unsafe.debug(", ");
            }
            final VmMethod method = getMethod(f);
            final VmType<?> vmClass = method.getDeclaringClass();
            Unsafe.debug(vmClass.getName());
            Unsafe.debug("::");
            Unsafe.debug(method.getName());
            Unsafe.debug('\n');
            f = getPrevious(f);
            max--;
        }
        if (isValid(f)) {
            Unsafe.debug("...");
        }
    }

    /**
     * Show the current stacktrace using Screen.debug.
     * TODO that method only exist to have line numbers : find a way to add line numbers to debugStackTrace(max)
     */
    @KernelSpace
    public final void debugStackTraceWithLineNumbers(int max) {
        final VmThread current = VmThread.currentThread();
        final VmStackFrame[] frames = (VmStackFrame[]) VmThread.getStackTrace(current);
        if (frames == null) {
            Unsafe.debug("Debug stacktrace:<no stack trace>\n");
        } else {
            Unsafe.debug("Debug stacktrace: ");
            for (VmStackFrame frame : frames) {
                final VmStackFrame s = (VmStackFrame) frame;
                Unsafe.debug(s.getMethod().getDeclaringClass().getName());
                Unsafe.debug("::");
                Unsafe.debug(s.getMethod().getName());
                Unsafe.debug(":");
                Unsafe.debug(s.getLocationInfo());
                Unsafe.debug('\n');
            }
        }
    }

    /**
     * Show the stacktrace of the given thread using Screen.debug.
     */
    @KernelSpace
    public final void debugStackTrace(VmThread thread) {
        Address f = thread.getStackFrame();
        Unsafe.debug("Debug stacktrace: ");
        boolean first = true;
        int max = 20;
        while (isValid(f) && (max > 0)) {
            if (first) {
                first = false;
            } else {
                Unsafe.debug(", ");
            }
            final VmMethod method = getMethod(f);
            final VmType vmClass = method.getDeclaringClass();
            Unsafe.debug(vmClass.getName());
            Unsafe.debug("::");
            Unsafe.debug(method.getName());
            f = getPrevious(f);
            max--;
        }
        if (isValid(f)) {
            Unsafe.debug("...");
        }
    }

    /**
     * Gets the offset within the frame of previous frame (if any)
     *
     * @param sf The stackframe to get the previous frame from.
     * @return The previous frame or null.
     */
    @KernelSpace
    protected abstract Offset getPreviousOffset(Address sf);

    /**
     * Gets the offset within the stackframe of compiled method id.
     *
     * @param sf Stackframe pointer
     * @return The method id offset
     */
    @KernelSpace
    protected abstract Offset getMethodIdOffset(Address sf);

    /**
     * Gets the offset within the stackframe of the return address.
     *
     * @param sf Stackframe pointer
     * @return The return address offset
     */
    @KernelSpace
    protected abstract Offset getReturnAddressOffset(Address sf);
}
TOP

Related Classes of org.jnode.vm.VmStackReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.