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:
parent
11d124882c
commit
8a084926e2
|
@ -31,126 +31,236 @@
|
||||||
package se.sics.cooja.mspmote.plugins;
|
package se.sics.cooja.mspmote.plugins;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.GridLayout;
|
import java.awt.Color;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.Observable;
|
import java.io.IOException;
|
||||||
import java.util.Observer;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JToggleButton;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
import se.sics.cooja.ClassDescription;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.GUI;
|
import se.sics.cooja.GUI;
|
||||||
import se.sics.cooja.Mote;
|
import se.sics.cooja.Mote;
|
||||||
import se.sics.cooja.MotePlugin;
|
import se.sics.cooja.MotePlugin;
|
||||||
|
import se.sics.cooja.MoteTimeEvent;
|
||||||
import se.sics.cooja.PluginType;
|
import se.sics.cooja.PluginType;
|
||||||
import se.sics.cooja.Simulation;
|
import se.sics.cooja.Simulation;
|
||||||
import se.sics.cooja.SupportedArguments;
|
import se.sics.cooja.SupportedArguments;
|
||||||
import se.sics.cooja.VisPlugin;
|
import se.sics.cooja.VisPlugin;
|
||||||
import se.sics.cooja.mspmote.MspMote;
|
import se.sics.cooja.mspmote.MspMote;
|
||||||
|
import se.sics.cooja.mspmote.MspMoteType;
|
||||||
import se.sics.mspsim.core.MSP430;
|
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.ui.StackUI;
|
||||||
import se.sics.mspsim.util.Utils;
|
|
||||||
|
|
||||||
@ClassDescription("Msp Stack Watcher")
|
@ClassDescription("Msp Stack Watcher")
|
||||||
@PluginType(PluginType.MOTE_PLUGIN)
|
@PluginType(PluginType.MOTE_PLUGIN)
|
||||||
@SupportedArguments(motes = {MspMote.class})
|
@SupportedArguments(motes = { MspMote.class })
|
||||||
public class MspStackWatcher extends VisPlugin implements MotePlugin {
|
public class MspStackWatcher extends VisPlugin implements MotePlugin {
|
||||||
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
|
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
|
||||||
|
|
||||||
private MspMote mspMote;
|
|
||||||
private MSP430 cpu;
|
|
||||||
private StackUI stackUI;
|
|
||||||
|
|
||||||
private Simulation simulation;
|
private Simulation simulation;
|
||||||
private Observer stackObserver = null;
|
private MSP430 cpu;
|
||||||
private JButton startButton;
|
private MspMote mspMote;
|
||||||
private JButton stopButton;
|
|
||||||
|
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) {
|
public MspStackWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
|
||||||
super("Msp Stack Watcher", gui);
|
super("Msp Stack Watcher: " + mote, gui);
|
||||||
this.mspMote = (MspMote) mote;
|
this.mspMote = (MspMote) mote;
|
||||||
cpu = mspMote.getCPU();
|
cpu = mspMote.getCPU();
|
||||||
simulation = simulationToVisualize;
|
simulation = simulationToVisualize;
|
||||||
|
|
||||||
getContentPane().setLayout(new BorderLayout());
|
getContentPane().setLayout(new BorderLayout());
|
||||||
|
|
||||||
// Register as stack observable
|
toggleButton = new JToggleButton("Click to monitor for stack overflows");
|
||||||
if (stackObserver == null) {
|
toggleButton.addActionListener(new ActionListener() {
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create stack overflow controls
|
|
||||||
startButton = new JButton("Stop simulation on stack overflow");
|
|
||||||
startButton.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
startButton.setEnabled(false);
|
if (toggleButton.isSelected()) {
|
||||||
stopButton.setEnabled(true);
|
toggleButton.setText("Monitoring for stack overflows");
|
||||||
|
if (!activate(true)) {
|
||||||
mspMote.monitorStack(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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stopButton = new JButton("Cancel");
|
/* Create Mspsim stack viewer */
|
||||||
stopButton.setEnabled(false);
|
stackUI = new StackUI(cpu, -1); /* Needs manual updates */
|
||||||
stopButton.addActionListener(new ActionListener() {
|
stackUI.init("Stack usage", mspMote.registry);
|
||||||
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);
|
|
||||||
stackUI.start();
|
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
|
add(BorderLayout.NORTH, memLabel);
|
||||||
/*if (logObserver == null && mspMote.getInterfaces().getLog() != null) {
|
add(BorderLayout.CENTER, stackUI);
|
||||||
mspMote.getInterfaces().getLog().addObserver(logObserver = new Observer() {
|
add(BorderLayout.SOUTH, toggleButton);
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
stackUI.addNote(mspMote.getInterfaces().getLog().getLastLogMessage());
|
setSize(400, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean activate(boolean gui) {
|
||||||
|
try {
|
||||||
|
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();
|
||||||
|
|
||||||
JPanel controlPanel = new JPanel(new GridLayout(2,1));
|
|
||||||
controlPanel.add(startButton);
|
|
||||||
controlPanel.add(stopButton);
|
|
||||||
|
|
||||||
add(BorderLayout.CENTER, stackUI);
|
|
||||||
add(BorderLayout.SOUTH, controlPanel);
|
|
||||||
|
|
||||||
setSize(240, 300);
|
|
||||||
|
|
||||||
// Tries to select this plugin
|
|
||||||
try {
|
|
||||||
setSelected(true);
|
|
||||||
} catch (java.beans.PropertyVetoException e) {
|
|
||||||
// Could not select
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
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() {
|
public void closePlugin() {
|
||||||
mspMote.getStackOverflowObservable().deleteObserver(stackObserver);
|
increasePosTimeEvent.remove();
|
||||||
stackUI.stop();
|
stackUI.stop();
|
||||||
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mote getMote() {
|
public Mote getMote() {
|
||||||
|
|
Loading…
Reference in a new issue