/*
* $Id$
*
* Copyright (C) 2003-2015 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.test.core;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.jnode.util.NumberUtils;
import org.jnode.vm.classmgr.Signature;
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.scheduler.VmThread;
import org.jnode.vm.x86.VmX86StackReader;
import org.jnode.vm.x86.VmX86Thread;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Offset;
/**
* @author Levente S\u00e1ntha
*/
public class StackView {
public static void main(String[] argv) {
String threadName = null;
if (argv.length > 0) {
threadName = argv[0];
}
Thread thread = null;
if (threadName == null) {
thread = Thread.currentThread();
} else {
// Find the root of the ThreadGroup tree
ThreadGroup grp = Thread.currentThread().getThreadGroup();
while (grp.getParent() != null) {
grp = grp.getParent();
}
final int max = grp.activeCount() * 2;
final Thread[] ts = new Thread[max];
grp.enumerate(ts);
for (int i = 0; i < max; i++) {
final Thread t = ts[i];
if (t != null) {
if (threadName.equals(t.getName())) {
thread = t;
break;
}
}
}
if (thread == null) {
System.out.println("Thread not found: " + threadName);
return;
}
}
VmThread vmThread = ThreadHelper.getVmThread(thread);
final int stackSize = vmThread.getStackSize();
final Object stack = invoke("getStack", VmThread.class, vmThread);
if (stack != null) {
final Address stackBottom = ObjectReference.fromObject(stack).toAddress();
final Address stackTop = stackBottom.add(stackSize);
final Address stackEnd;
if (vmThread == VmThread.currentThread()) {
stackEnd = stackBottom;
} else {
stackEnd = ((VmX86Thread) vmThread).getStackPointer();
}
final int slotSize = (Integer) invoke("getReferenceSize", VmX86Thread.class, vmThread);
Address stackFrame = vmThread.getStackFrame();
System.out.println("Stack start: " + NumberUtils.hex(stackTop.toInt()));
System.out.println("Stack end : " + NumberUtils.hex(stackEnd.toInt()));
System.out.println("Raw stack:");
Address ptr = stackTop;
while (ptr.GE(stackEnd)) {
final Address child = ptr.loadAddress();
if (child != null) {
System.out.print(NumberUtils.hex(ptr.toInt()) + " ");
if (VmUtils.getVm().getHeapManager().isObject(child)) {
System.out.println(child);
} else {
System.out.println(NumberUtils.hex(child.toInt()));
}
}
ptr = ptr.sub(slotSize);
}
System.out.println("Stack frames:");
VmX86StackReader sr = new VmX86StackReader(slotSize);
Address currFrame = stackFrame;
//Address prevFrame = null;
do {
ptr = currFrame;
//ccid
ptr = ptr.add(Offset.fromIntSignExtend(VmX86StackReader.METHOD_ID_OFFSET * slotSize));
int ccid = ptr.loadInt();
if (ccid == 0) {
//invalid farme, exit
break;
}
System.out.println("--------------------------------------------------------------------------");
System.out.println("Stack frame: " + NumberUtils.hex(stackFrame.toInt()));
VmCompiledCode cc = VmUtils.getVm().getCompiledMethods().get(ccid);
VmMethod vmMethod = cc.getMethod();
int noArguments = vmMethod.getNoArguments();
VmType[] args = new VmType[noArguments];
for (int i = 0; i < noArguments; i++) {
args[i] = vmMethod.getArgumentType(i);
}
System.out.print(NumberUtils.hex(ptr.toInt()) + " ");
System.out.println(vmMethod.getDeclaringClass().getName() + "." + vmMethod.getName() +
Signature.toSignature(vmMethod.getReturnType(), args));
ptr = ptr.sub(Offset.fromIntSignExtend(VmX86StackReader.METHOD_ID_OFFSET * slotSize));
//old EBP
System.out.println("Previous frame");
ptr = ptr.add(Offset.fromIntSignExtend(VmX86StackReader.PREVIOUS_OFFSET * slotSize));
System.out.print(NumberUtils.hex(ptr.toInt()) + " ");
System.out.println(NumberUtils.hex(ptr.loadInt()));
ptr = ptr.sub(Offset.fromIntSignExtend(VmX86StackReader.PREVIOUS_OFFSET * slotSize));
//return Address
System.out.println("Return address");
ptr = ptr.add(Offset.fromIntSignExtend(VmX86StackReader.RETURNADDRESS_OFFSET * slotSize));
System.out.print(NumberUtils.hex(ptr.toInt()) + " ");
System.out.println(NumberUtils.hex(ptr.loadInt()));
//method argumants
int sc = vmMethod.getArgSlotCount();
System.out.println("Method arguments: " + sc);
for (int i = 0; i < sc; i++) {
ptr = ptr.add(slotSize);
System.out.print(NumberUtils.hex(ptr.toInt()) + " Arg" + (i + 1) + " = ");
Address child = ptr.loadAddress();
if (VmUtils.getVm().getHeapManager().isObject(child)) {
System.out.println("Class: " + child.getClass() + " Value: " + child);
} else {
System.out.println(NumberUtils.hex(child.toInt()));
}
//System.out.println(NumberUtils.hex(ptr.loadInt()));
}
} while ((currFrame = sr.getPrevious(currFrame)) != null);
} else {
System.out.println("Stack is null");
}
}
private static Object invoke(String methodName, Class clazz, Object instance) {
try {
Method met = clazz.getMethod(methodName);
return met.invoke(instance);
} catch (Exception x) {
x.printStackTrace();
throw new RuntimeException(x);
}
}
private static Object get(String filedName, Class clazz, Object instance) {
try {
Field field = clazz.getField(filedName);
return field.get(instance);
} catch (Exception x) {
x.printStackTrace();
throw new RuntimeException(x);
}
}
}