re-implemented stack overflow monitoring, and user can now manually override the stack addresses for use with

custom linker scripts
This commit is contained in:
Fredrik Osterlind 2013-08-14 13:03:15 +02:00
parent 11d124882c
commit 8a084926e2

View file

@ -31,126 +31,236 @@
package se.sics.cooja.mspmote.plugins;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.ClassDescription;
import se.sics.cooja.GUI;
import se.sics.cooja.Mote;
import se.sics.cooja.MotePlugin;
import se.sics.cooja.MoteTimeEvent;
import se.sics.cooja.PluginType;
import se.sics.cooja.Simulation;
import se.sics.cooja.SupportedArguments;
import se.sics.cooja.VisPlugin;
import se.sics.cooja.mspmote.MspMote;
import se.sics.cooja.mspmote.MspMoteType;
import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.core.Memory.AccessMode;
import se.sics.mspsim.core.RegisterMonitor;
import se.sics.mspsim.ui.StackUI;
import se.sics.mspsim.util.Utils;
@ClassDescription("Msp Stack Watcher")
@PluginType(PluginType.MOTE_PLUGIN)
@SupportedArguments(motes = {MspMote.class})
@SupportedArguments(motes = { MspMote.class })
public class MspStackWatcher extends VisPlugin implements MotePlugin {
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
private MspMote mspMote;
private MSP430 cpu;
private StackUI stackUI;
private Simulation simulation;
private Observer stackObserver = null;
private JButton startButton;
private JButton stopButton;
private MSP430 cpu;
private MspMote mspMote;
private StackUI stackUI;
private RegisterMonitor.Adapter registerMonitor = null;
private JToggleButton toggleButton;
private MoteTimeEvent increasePosTimeEvent;
private Integer userOverriddenStack = null;
private JLabel memLabel = new JLabel("");
public MspStackWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
super("Msp Stack Watcher", gui);
super("Msp Stack Watcher: " + mote, gui);
this.mspMote = (MspMote) mote;
cpu = mspMote.getCPU();
simulation = simulationToVisualize;
getContentPane().setLayout(new BorderLayout());
// Register as stack observable
if (stackObserver == null) {
mspMote.getStackOverflowObservable().addObserver(stackObserver = new Observer() {
public void update(Observable obs, Object obj) {
simulation.stopSimulation();
JOptionPane.showMessageDialog(
MspStackWatcher.this,
"Bad memory access!\nSimulation stopped.\n" +
"\nCurrent stack pointer = 0x" + Utils.hex16(cpu.reg[MSP430.SP]) +
"\nStart of heap = 0x" + Utils.hex16(cpu.getDisAsm().getMap().heapStartAddress),
"Stack overflow", JOptionPane.ERROR_MESSAGE
);
toggleButton = new JToggleButton("Click to monitor for stack overflows");
toggleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (toggleButton.isSelected()) {
toggleButton.setText("Monitoring for stack overflows");
if (!activate(true)) {
toggleButton.setBackground(Color.RED);
toggleButton.setText("Monitoring for stack overflows - FAILED!");
toggleButton.setSelected(false);
}
toggleButton.setBackground(null);
} else {
toggleButton.setBackground(null);
toggleButton.setText("Click to monitor for stack overflows");
deactivate();
}
});
}
// Create stack overflow controls
startButton = new JButton("Stop simulation on stack overflow");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
mspMote.monitorStack(true);
}
});
stopButton = new JButton("Cancel");
stopButton.setEnabled(false);
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
mspMote.monitorStack(false);
}
});
// Create nfi's stack viewer
stackUI = new StackUI(cpu);
stackUI.init("MSPSim stack", mspMote.registry);
/* Create Mspsim stack viewer */
stackUI = new StackUI(cpu, -1); /* Needs manual updates */
stackUI.init("Stack usage", mspMote.registry);
stackUI.start();
increasePosTimeEvent = new MoteTimeEvent(mspMote, 0) {
public void execute(long t) {
stackUI.requestIncreasePos();
simulation.scheduleEvent(this, t + Simulation.MILLISECOND);
}
};
simulation.scheduleEvent(increasePosTimeEvent, simulation.getSimulationTime());
// Register as log listener
/*if (logObserver == null && mspMote.getInterfaces().getLog() != null) {
mspMote.getInterfaces().getLog().addObserver(logObserver = new Observer() {
public void update(Observable obs, Object obj) {
stackUI.addNote(mspMote.getInterfaces().getLog().getLastLogMessage());
}
});
}*/
JPanel controlPanel = new JPanel(new GridLayout(2,1));
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(BorderLayout.NORTH, memLabel);
add(BorderLayout.CENTER, stackUI);
add(BorderLayout.SOUTH, controlPanel);
add(BorderLayout.SOUTH, toggleButton);
setSize(240, 300);
setSize(400, 300);
}
// Tries to select this plugin
private boolean activate(boolean gui) {
try {
setSelected(true);
} catch (java.beans.PropertyVetoException e) {
// Could not select
int stack = ((MspMoteType) mspMote.getType()).getELF().getMap().stackStartAddress;
if (gui) {
String s = (String)JOptionPane.showInputDialog(
GUI.getTopParentContainer(),
"With default linker scripts the stack starts at 0x" + Integer.toHexString(stack) + ".\n" +
"If you are using a modified linker script, you may here correct the stack start address.",
"Enter stack start address",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"0x" + Integer.toHexString(userOverriddenStack!=null?userOverriddenStack:stack));
userOverriddenStack = null;
if (s != null) {
try {
int newStack = Integer.decode(s);
if (newStack != stack) {
userOverriddenStack = newStack;
}
} catch (Exception e) {
logger.error("Error parsing provided stack address: " + s, e);
return false;
}
}
}
if (userOverriddenStack != null) {
stack = userOverriddenStack;
}
int heap = ((MspMoteType) mspMote.getType()).getELF().getMap().heapStartAddress;
if (stack < 0) {
stack = cpu.config.ramStart + cpu.config.ramSize;
}
logger.debug("SP starts at: 0x" + Integer.toHexString(stack));
logger.debug("Heap starts at: 0x" + Integer.toHexString(heap));
logger.debug("Available stack: " + (stack-heap) + " bytes");
memLabel.setText(String.format("Stack 0x%x, heap 0x%x", stack, heap));
if (stack < 0 || heap < 0) {
return false;
}
/*final int stackStartAddress = stack;*/
final int heapStartAddress = heap;
registerMonitor = new RegisterMonitor.Adapter() {
int min = Integer.MAX_VALUE;
public void notifyWriteBefore(int register, final int sp, AccessMode mode) {
/*logger.debug("SP is now: 0x" + Integer.toHexString(sp));*/
final int available = sp - heapStartAddress;
if (available < min) {
min = available;
String details = mspMote.getExecutionDetails();
if (details != null) {
logger.info(String.format(mspMote + ": Maximum stack usage: 0x%x, available stack 0x%x", sp, available));
logger.info(details);
}
}
if (available <= 0) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
String.format("Stack overflow!\n\n" +
"\tSP = 0x%05x\n" +
"\tHeap start = 0x%05x\n\n" +
"\tAvailable = %d\n", sp, heapStartAddress, available),
"Stack overflow on " + mspMote,
JOptionPane.ERROR_MESSAGE);
}
});
simulation.stopSimulation();
}
}
};
cpu.addRegisterWriteMonitor(MSP430.SP, registerMonitor);
} catch (IOException e) {
logger.warn("Stack monitoring failed: " + e.getMessage(), e);
registerMonitor = null;
return false;
}
return true;
}
private void deactivate() {
userOverriddenStack = null;
if (registerMonitor != null) {
cpu.removeRegisterWriteMonitor(MSP430.SP, registerMonitor);
registerMonitor = null;
}
}
public Collection<Element> getConfigXML() {
ArrayList<Element> config = new ArrayList<Element>();
Element element;
if (userOverriddenStack != null) {
element = new Element("stack");
element.setText("0x" + Integer.toHexString(userOverriddenStack));
config.add(element);
}
element = new Element("monitoring");
element.setText("" + toggleButton.isSelected());
config.add(element);
return config;
}
public boolean setConfigXML(Collection<Element> configXML,
boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("monitoring")) {
boolean monitor = Boolean.parseBoolean(element.getText());
if (monitor) {
if (activate(false)) {
toggleButton.setSelected(true);
}
}
} else if (element.getName().equals("stack")) {
userOverriddenStack = Integer.decode(element.getText());
}
}
return true;
}
public void closePlugin() {
mspMote.getStackOverflowObservable().deleteObserver(stackObserver);
increasePosTimeEvent.remove();
stackUI.stop();
deactivate();
}
public Mote getMote() {