crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/containers/StackEntry.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 0 5ad7ad99af01
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/

package com.nokia.s60tools.crashanalyser.containers;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.nokia.s60tools.crashanalyser.containers.Process.StackItems;
import com.nokia.s60tools.crashanalyser.model.XmlUtils;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.*;

/**
 * Represents one entry in a stack. 
 *
 */
public final class StackEntry {
	
	// XML tags
	public static final String TAG_ADDRESS = "address";
	public static final String TAG_VALUE = "value";
	public static final String TAG_OFFSET = "offset";
	public static final String TAG_TEXT = "text";
	public static final String TAG_ACCURATE = "accurate";
	public static final String TAG_LINK = "link";
	public static final String TAG_OUTSIDE_STACK_BOUNDS = "outside_current_stack_pointer_range";
	public static final String TAG_CURRENT_STACK_POINTER = "current_stack_pointer";
	public static final String ATTRIBUTE_SEG = "seg";
	public static final String SEGMENT_SYMBOLS = "seg_symbols";
	public static final String SEGMENT_REGISTERS = "seg_registers";
	
	static final String FORMAT = "%-10s  %-10s  %-6s  %-6s  %s  %s";

	// Data
	private final String stackEntryAddress;
	private final String stackEntryValue;
	private final String stackEntrySymbol;
	private final String stackEntryObject;
	private final String stackEntryOffset;
	private final String stackEntryText;
	private final String stackEntrySource;
	private final String stackEntryCodeSegmentName; 
	private final boolean outsideStackBounds;
	private final boolean currentStackPointer;
	private final boolean accurate;
	private final boolean xipSymbol;
	private final boolean registerBased;
	
	private StackEntry(final String address, final String value, final String symbol, final String object, final String offset, final String text, final String source,
						final String codeSegmentName, final boolean outsideSB, final boolean currentSP, final boolean isAccurate, final boolean xip, final boolean register) {
		stackEntryAddress = address;
		stackEntryValue = value;
		stackEntrySymbol = symbol;
		stackEntryObject = object;
		stackEntryOffset = offset;
		stackEntryText = text;
		stackEntrySource = source;
		stackEntryCodeSegmentName = codeSegmentName;
		outsideStackBounds = outsideSB;
		currentStackPointer = currentSP;
		accurate = isAccurate;
		xipSymbol = xip;
		registerBased = register;
	}
	
	public String getAddress() {
		return stackEntryAddress;
	}
	
	public String getValue() {
		return stackEntryValue;
	}
	
	public String getSymbol() {
		return stackEntrySymbol;
	}
	
	public String getObject() {
		return stackEntryObject;
	}
	
	public String getOffset() {
		return stackEntryOffset;
	}
	
	public String getText() {
		return stackEntryText;
	}
	
	public String getSource() {
		return stackEntrySource;
	}
	
	public boolean outsideStackBounds() {
		return outsideStackBounds;
	}
	
	public boolean currentStackPointer() {
		return currentStackPointer;
	}
	
	public boolean accurate() {
		return accurate;
	}
	
	public boolean xip() {
		return xipSymbol;
	}
	
	public boolean registerBased() {
		return registerBased;
	}
	
	public String getCodeSegmentName() {
		return stackEntryCodeSegmentName;
	}
	
	@Override
	public String toString() {
		return stackEntrySource;
	}	
	
	/**
	 * Writes stack item into given buffer (i.e. text file)
	 * @param out
	 * @param stackItems
	 * @param stack
	 * @param html
	 * @throws IOException
	 */
	public void writeTo(final BufferedWriter out, final StackItems stackItems, final Stack stack, final boolean html) throws IOException {
		if (currentStackPointer) {
			writeLine(out, "");
			if (html)
				writeLine(out, "</pre><a name=\"STACKPOINTER\"><h3><<<<<<<<<< CURRENT STACK POINTER >>>>>>>>>></h3></a><pre>");
			else
				writeLine(out, "<<<<<<<<<< CURRENT STACK POINTER >>>>>>>>>>");
			writeLine(out, "");
			writeLine(out, String.format(FORMAT, stackEntryAddress, 
					 stackEntryValue,
					 stackEntryText,
					 stackEntryOffset,
					 stackEntryObject,
					 stackEntrySymbol));

			if (!"".equals(stack.getLinkRegister()) || 
				!"".equals(stack.getStackPointer()) || 
				!"".equals(stack.getProgramCounter())) {
				writeLine(out, "");
				if (!"".equals(stack.getLinkRegister())) {
					writeLine(out, "LR :" + stack.getLinkRegister());
				}
				if (!"".equals(stack.getProgramCounter())) {
					writeLine(out, "PC :" + stack.getProgramCounter());
				}
				if (!"".equals(stack.getStackPointer())) {
					writeLine(out, "SP :" + stack.getStackPointer());
				}
			}
			writeLine(out, "");
			if (html)
				writeLine(out, "</pre><h3><<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>></h3><pre>"); // just to make it look nice
			else
				writeLine(out, "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>");
			writeLine(out, "");
		} else if (StackItems.ACCURATE.equals(stackItems) && !accurate) {
			return;
		} else if (StackItems.SYMBOLS.equals(stackItems) && "".equals(stackEntrySymbol)) {
			return;
		} else {
			writeLine(out, String.format(FORMAT, stackEntryAddress, 
												 stackEntryValue,
												 stackEntryText,
												 stackEntryOffset,
												 stackEntryObject,
												 stackEntrySymbol));
		}
	}	
	
	void writeLine(final BufferedWriter out, final String line) throws IOException {
		out.write(line);
		out.newLine();
	}

	/**
	 * Reads and creates stack entry from stack entry xml element
	 * @param elementStackEntry
	 * @param symbols
	 * @param registers
	 * @return created stack entry or null
	 */
	public static StackEntry read(final Element elementStackEntry, 
									final Map<Integer, Symbol> symbols,
									final Map<Integer, Register> registers) {
		try {
			// read address if exists
			String address = XmlUtils.getTextValue(elementStackEntry, TAG_ADDRESS);
			if (address == null)
				address = "";
			
			// read value if exists
			String value = XmlUtils.getTextValue(elementStackEntry, TAG_VALUE);
			if (value == null)
				value = "";
			
			boolean xip = false;
			boolean registerBased = false;
			String symbol = "";
			String object = "";
			String source = "";
			String codeSegment = "";
			
			// try to read symbol & register information for this stack entry
			final NodeList nl = elementStackEntry.getElementsByTagName(TAG_LINK);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					final Node linkNode = nl.item(i);
					final String nodeValue = XmlUtils.getNodeValue(linkNode);
					final NamedNodeMap attributes = linkNode.getAttributes();
					if (attributes != null && attributes.getLength() > 0) {
						final Node seg = attributes.getNamedItem(ATTRIBUTE_SEG);
						// symbol id
						if (SEGMENT_SYMBOLS.equals(XmlUtils.getNodeValue(seg))) {
							try {
								final int sId = Integer.parseInt(nodeValue);
								if (symbols.containsKey(sId)) {
									final Symbol sym = symbols.get(sId);
									symbol = sym.getName();
									object = sym.getObject();
									source = sym.getSource();
									xip = sym.xip();
									codeSegment = sym.getCodeSegmentName();
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						// register id
						} else if (SEGMENT_REGISTERS.equals(XmlUtils.getNodeValue(seg))) {
							registerBased = true;
							final int rId = Integer.parseInt(nodeValue);
							if (registers.containsKey(rId)) {
								final Register reg = registers.get(rId);
								if ("R14".equals(reg.getName())) {
									address = "LR";
								} else if ("R15".equals(reg.getName())) {
									address = "PC";
								}
							}
						}
					}
				}
			}
			
			final boolean currentStackPointer = XmlUtils.containsNode(elementStackEntry, TAG_CURRENT_STACK_POINTER);
			final boolean accurate = XmlUtils.containsNode(elementStackEntry, TAG_ACCURATE);
			final boolean outsideStackBounds = XmlUtils.containsNode(elementStackEntry, TAG_OUTSIDE_STACK_BOUNDS);
	
			// read offset if exists
			String offset = XmlUtils.getTextValue(elementStackEntry, TAG_OFFSET);
			if (offset == null)
				offset = "";
			
			// read text if exists
			String text = XmlUtils.getTextValue(elementStackEntry, TAG_TEXT);
			if (text == null)
				text = "";
			
			return new StackEntry(address, value, symbol, object, offset, text, source, codeSegment,
									outsideStackBounds, currentStackPointer, accurate, xip, registerBased);
		} catch (Exception e) {
			return null;
		}
	}
}