mspsim motes now implements new WatchpointMote interface, simplified code

This commit is contained in:
Fredrik Osterlind 2012-03-21 16:57:04 +01:00
parent 088f2e12a8
commit 2e583c733e
4 changed files with 274 additions and 440 deletions

View file

@ -32,10 +32,10 @@
package se.sics.cooja.mspmote; package se.sics.cooja.mspmote;
import java.io.File; import java.io.File;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import se.sics.cooja.MoteInterfaceHandler;
import se.sics.cooja.Simulation; import se.sics.cooja.Simulation;
import se.sics.cooja.interfaces.*;
import se.sics.mspsim.platform.esb.ESBNode; import se.sics.mspsim.platform.esb.ESBNode;
/** /**

View file

@ -31,12 +31,13 @@
package se.sics.cooja.mspmote; package se.sics.cooja.mspmote;
import java.awt.event.ActionListener;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Observable; import java.util.Observable;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -56,14 +57,12 @@ import se.sics.cooja.interfaces.IPAddress;
import se.sics.cooja.motes.AbstractEmulatedMote; import se.sics.cooja.motes.AbstractEmulatedMote;
import se.sics.cooja.mspmote.interfaces.MspSerial; import se.sics.cooja.mspmote.interfaces.MspSerial;
import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin; import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin;
import se.sics.cooja.mspmote.plugins.MspBreakpointContainer; import se.sics.cooja.mspmote.plugins.MspBreakpoint;
import se.sics.cooja.plugins.BufferListener.BufferAccess;
import se.sics.cooja.plugins.Visualizer; import se.sics.cooja.plugins.Visualizer;
import se.sics.mspsim.cli.CommandContext; import se.sics.mspsim.cli.CommandContext;
import se.sics.mspsim.cli.CommandHandler; import se.sics.mspsim.cli.CommandHandler;
import se.sics.mspsim.cli.LineListener; import se.sics.mspsim.cli.LineListener;
import se.sics.mspsim.cli.LineOutputStream; import se.sics.mspsim.cli.LineOutputStream;
import se.sics.mspsim.core.CPUMonitor;
import se.sics.mspsim.core.EmulationException; import se.sics.mspsim.core.EmulationException;
import se.sics.mspsim.core.MSP430; import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.core.MSP430Constants; import se.sics.mspsim.core.MSP430Constants;
@ -103,15 +102,11 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
private int heapStartAddress; private int heapStartAddress;
private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable(); private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable();
private MspBreakpointContainer breakpointsContainer;
public MspMote() { public MspMote() {
myMoteType = null; myMoteType = null;
myCpu = null; myCpu = null;
myMemory = null; myMemory = null;
myMoteInterfaceHandler = null; myMoteInterfaceHandler = null;
/* Scheduled from setConfigXML */
} }
public MspMote(MspMoteType moteType, Simulation simulation) { public MspMote(MspMoteType moteType, Simulation simulation) {
@ -130,9 +125,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* TODO Setup COOJA-specific window manager */ /* TODO Setup COOJA-specific window manager */
registry.registerComponent("windowManager", new JFrameWindowManager()); registry.registerComponent("windowManager", new JFrameWindowManager());
/* Create watchpoint container */
try { try {
breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo()); debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
} catch (IOException e) { } catch (IOException e) {
throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e); throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e);
} }
@ -300,7 +294,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
if (stopNextInstruction) { if (stopNextInstruction) {
stopNextInstruction = false; stopNextInstruction = false;
/*sendCLICommandAndPrint("trace 1000");*/ /* TODO Enable */
scheduleNextWakeup(t); scheduleNextWakeup(t);
throw new RuntimeException("MSPSim requested simulation stop"); throw new RuntimeException("MSPSim requested simulation stop");
} }
@ -333,6 +326,10 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/*logger.debug(t + ": Schedule next wakeup at " + nextExecute);*/ /*logger.debug(t + ": Schedule next wakeup at " + nextExecute);*/
scheduleNextWakeup(nextExecute); scheduleNextWakeup(nextExecute);
if (stopNextInstruction) {
stopNextInstruction = false;
throw new RuntimeException("MSPSim requested simulation stop");
}
/* XXX TODO Reimplement stack monitoring using MSPSim internals */ /* XXX TODO Reimplement stack monitoring using MSPSim internals */
/*if (monitorStackUsage) { /*if (monitorStackUsage) {
@ -391,9 +388,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
myMoteInterfaceHandler = createMoteInterfaceHandler(); myMoteInterfaceHandler = createMoteInterfaceHandler();
} }
/* Create watchpoint container */
try { try {
breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo()); debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
} catch (IOException e) { } catch (IOException e) {
throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e); throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e);
} }
@ -404,7 +400,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
if (name.equals("motetype_identifier")) { if (name.equals("motetype_identifier")) {
/* Ignored: handled by simulation */ /* Ignored: handled by simulation */
} else if ("breakpoints".equals(element.getName())) { } else if ("breakpoints".equals(element.getName())) {
breakpointsContainer.setConfigXML(element.getChildren(), visAvailable); setWatchpointConfigXML(element.getChildren(), visAvailable);
} else if (name.equals("interface_config")) { } else if (name.equals("interface_config")) {
String intfClass = element.getText().trim(); String intfClass = element.getText().trim();
if (intfClass.equals("se.sics.cooja.mspmote.interfaces.MspIPAddress")) { if (intfClass.equals("se.sics.cooja.mspmote.interfaces.MspIPAddress")) {
@ -440,7 +436,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* Breakpoints */ /* Breakpoints */
element = new Element("breakpoints"); element = new Element("breakpoints");
element.addContent(breakpointsContainer.getConfigXML()); element.addContent(getWatchpointConfigXML());
config.add(element); config.add(element);
// Mote interfaces // Mote interfaces
@ -458,39 +454,13 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
return config; return config;
} }
/* Watchpoints: Forward to breakpoint container */
public void addWatchpointListener(ActionListener listener) {
breakpointsContainer.addWatchpointListener(listener);
}
public Watchpoint getLastWatchpoint() {
return breakpointsContainer.getLastWatchpoint();
}
public Mote getMote() {
return breakpointsContainer.getMote();
}
public ActionListener[] getWatchpointListeners() {
return breakpointsContainer.getWatchpointListeners();
}
public void removeWatchpointListener(ActionListener listener) {
breakpointsContainer.removeWatchpointListener(listener);
}
public MspBreakpointContainer getBreakpointsContainer() {
return breakpointsContainer;
}
public String getExecutionDetails() { public String getExecutionDetails() {
return executeCLICommand("stacktrace"); return executeCLICommand("stacktrace");
} }
public String getPCString() { public String getPCString() {
int pc = myCpu.getPC(); int pc = myCpu.getPC();
ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class); ELF elf = myCpu.getRegistry().getComponent(ELF.class);
DebugInfo di = elf.getDebugInfo(pc); DebugInfo di = elf.getDebugInfo(pc);
/* Following code examples from MSPsim, DebugCommands.java */ /* Following code examples from MSPsim, DebugCommands.java */
@ -539,4 +509,144 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/*return executeCLICommand("line " + myCpu.getPC());*/ /*return executeCLICommand("line " + myCpu.getPC());*/
} }
/* WatchpointMote */
private ArrayList<WatchpointListener> watchpointListeners = new ArrayList<WatchpointListener>();
private ArrayList<MspBreakpoint> watchpoints = new ArrayList<MspBreakpoint>();
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null;
public void addWatchpointListener(WatchpointListener listener) {
watchpointListeners.add(listener);
}
public void removeWatchpointListener(WatchpointListener listener) {
watchpointListeners.remove(listener);
}
public WatchpointListener[] getWatchpointListeners() {
return watchpointListeners.toArray(new WatchpointListener[0]);
}
public Watchpoint addBreakpoint(File codeFile, int lineNr, int address) {
MspBreakpoint bp = new MspBreakpoint(this, address, codeFile, new Integer(lineNr));
watchpoints.add(bp);
for (WatchpointListener listener: watchpointListeners) {
listener.watchpointsChanged();
}
return bp;
}
public void removeBreakpoint(Watchpoint watchpoint) {
((MspBreakpoint)watchpoint).unregisterBreakpoint();
watchpoints.remove(watchpoint);
for (WatchpointListener listener: watchpointListeners) {
listener.watchpointsChanged();
}
}
public Watchpoint[] getBreakpoints() {
return watchpoints.toArray(new Watchpoint[0]);
}
public boolean breakpointExists(int address) {
if (address < 0) {
return false;
}
for (Watchpoint watchpoint: watchpoints) {
if (watchpoint.getExecutableAddress() == address) {
return true;
}
}
return false;
}
public boolean breakpointExists(File file, int lineNr) {
for (Watchpoint watchpoint: watchpoints) {
if (watchpoint.getCodeFile() == null) {
continue;
}
if (watchpoint.getCodeFile().compareTo(file) != 0) {
continue;
}
if (watchpoint.getLineNumber() != lineNr) {
continue;
}
return true;
}
return false;
}
public Integer getExecutableAddressOf(File file, int lineNr) {
if (file == null || lineNr < 0 || debuggingInfo == null) {
return null;
}
/* Match file */
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
if (lineTable == null) {
Enumeration<File> fileEnum = debuggingInfo.keys();
while (fileEnum.hasMoreElements()) {
File f = fileEnum.nextElement();
if (f != null && f.getName().equals(file.getName())) {
lineTable = debuggingInfo.get(f);
break;
}
}
}
if (lineTable == null) {
return null;
}
/* Match line number */
Integer address = lineTable.get(lineNr);
if (address != null) {
Enumeration<Integer> lineEnum = lineTable.keys();
while (lineEnum.hasMoreElements()) {
Integer l = lineEnum.nextElement();
if (l != null && l.intValue() == lineNr) {
/* Found line address */
return lineTable.get(l);
}
}
}
return null;
}
public void signalBreakpointTrigger(MspBreakpoint b) {
if (b.stopsSimulation() && getSimulation().isRunning()) {
/* Stop simulation immediately */
stopNextInstruction();
}
/* Notify listeners */
WatchpointListener[] listeners = getWatchpointListeners();
for (WatchpointListener listener: listeners) {
listener.watchpointTriggered(b);
}
}
public Collection<Element> getWatchpointConfigXML() {
ArrayList<Element> config = new ArrayList<Element>();
Element element;
for (MspBreakpoint breakpoint: watchpoints) {
element = new Element("breakpoint");
element.addContent(breakpoint.getConfigXML());
config.add(element);
}
return config;
}
public boolean setWatchpointConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("breakpoint")) {
MspBreakpoint breakpoint = new MspBreakpoint(this);
if (!breakpoint.setConfigXML(element.getChildren(), visAvailable)) {
logger.warn("Could not restore breakpoint: " + breakpoint);
} else {
watchpoints.add(breakpoint);
}
}
}
return true;
}
} }

View file

@ -34,101 +34,125 @@ package se.sics.cooja.mspmote.plugins;
import java.awt.Color; import java.awt.Color;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Vector;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jdom.Element; import org.jdom.Element;
import se.sics.cooja.Watchpoint; import se.sics.cooja.Watchpoint;
import se.sics.cooja.mspmote.MspMote; import se.sics.cooja.mspmote.MspMote;
import se.sics.cooja.util.StringUtils;
import se.sics.mspsim.core.CPUMonitor; import se.sics.mspsim.core.CPUMonitor;
/** /**
* Breakpoint. * Mspsim watchpoint.
* Contains meta data such source code file and line number.
* *
* @author Fredrik Osterlind * @author Fredrik Osterlind
*/ */
public class MspBreakpoint implements Watchpoint { public class MspBreakpoint implements Watchpoint {
private static Logger logger = Logger.getLogger(MspBreakpoint.class); private static Logger logger = Logger.getLogger(MspBreakpoint.class);
private MspBreakpointContainer breakpoints;
private MspMote mspMote; private MspMote mspMote;
private int address = -1; /* Binary address */
private File codeFile = null; /* Source code, may be null*/
private int lineNr = -1; /* Source code line number, may be null */
private CPUMonitor cpuMonitor = null; private CPUMonitor cpuMonitor = null;
private boolean stopsSimulation = true; private boolean stopsSimulation = true;
private Integer address = null; /* Binary address */
private File codeFile = null; /* Source code, may be null*/
private Integer lineNr = null; /* Source code line number, may be null */
private String msg = null; private String msg = null;
private Color color = Color.BLACK; private Color color = Color.BLACK;
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote) { private String contikiCode = null;
this.breakpoints = breakpoints;
public MspBreakpoint(MspMote mote) {
this.mspMote = mote; this.mspMote = mote;
/* expects setConfigXML(..) */
} }
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address) { public MspBreakpoint(MspMote mote, Integer address, File codeFile, Integer lineNr) {
this(breakpoints, mote); this(mote);
this.address = address; this.address = address;
this.codeFile = codeFile;
this.lineNr = lineNr;
createMonitor(); createMonitor();
} }
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address, File codeFile, Integer lineNr) {
this(breakpoints, mote, address);
this.codeFile = codeFile;
this.lineNr = lineNr;
}
/**
* @return MSP mote
*/
public MspMote getMote() { public MspMote getMote() {
return mspMote; return mspMote;
} }
/** public Color getColor() {
* @return Executable address return color;
*/ }
public Integer getExecutableAddress() { public void setColor(Color color) {
return address; this.color = color;
}
public String getDescription() {
String desc = "";
if (codeFile != null) {
desc += codeFile.getPath() + ":" + lineNr + " (0x" + Integer.toHexString(address) + ")";
} else if (address >= 0) {
desc += "0x" + Integer.toHexString(address);
}
if (msg != null) {
desc += "\n\n" + msg;
}
return desc;
}
public void setUserMessage(String msg) {
this.msg = msg;
}
public String getUserMessage() {
return msg;
} }
/**
* @return Source code file
*/
public File getCodeFile() { public File getCodeFile() {
return codeFile; return codeFile;
} }
public int getLineNumber() {
/**
* @return Source code file line number
*/
public Integer getLineNumber() {
return lineNr; return lineNr;
} }
public int getExecutableAddress() {
public boolean stopsSimulation() { return address;
return stopsSimulation;
} }
public void setStopsSimulation(boolean stops) { public void setStopsSimulation(boolean stops) {
stopsSimulation = stops; stopsSimulation = stops;
} }
public boolean stopsSimulation() {
return stopsSimulation;
}
private void createMonitor() { private void createMonitor() {
cpuMonitor = new CPUMonitor() { cpuMonitor = new CPUMonitor() {
public void cpuAction(int type, int adr, int data) { public void cpuAction(int type, int adr, int data) {
breakpoints.signalBreakpointTrigger(MspBreakpoint.this); if (type != CPUMonitor.EXECUTE) {
return;
}
mspMote.signalBreakpointTrigger(MspBreakpoint.this);
} }
}; };
mspMote.getCPU().addWatchPoint(address, cpuMonitor); mspMote.getCPU().addWatchPoint(address, cpuMonitor);
/* Remember Contiki code, to verify it when reloaded */
if (contikiCode == null) {
final String code = StringUtils.loadFromFile(codeFile);
if (code != null) {
String[] lines = code.split("\n");
if (lineNr-1 < lines.length) {
contikiCode = lines[lineNr-1].trim();
}
}
}
} }
public void unregisterBreakpoint() { public void unregisterBreakpoint() {
@ -136,27 +160,25 @@ public class MspBreakpoint implements Watchpoint {
} }
public Collection<Element> getConfigXML() { public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>(); ArrayList<Element> config = new ArrayList<Element>();
Element element; Element element;
element = new Element("address");
element.setText(address.toString());
config.add(element);
element = new Element("stops"); element = new Element("stops");
element.setText("" + stopsSimulation); element.setText("" + stopsSimulation);
config.add(element); config.add(element);
if (codeFile != null) {
element = new Element("codefile"); element = new Element("codefile");
File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile); File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile);
element.setText(file.getPath().replaceAll("\\\\", "/")); element.setText(file.getPath().replaceAll("\\\\", "/"));
config.add(element); config.add(element);
}
if (lineNr != null) {
element = new Element("line"); element = new Element("line");
element.setText(lineNr.toString()); element.setText("" + lineNr);
config.add(element);
if (contikiCode != null) {
element = new Element("contikicode");
element.setText(contikiCode);
config.add(element); config.add(element);
} }
@ -193,8 +215,23 @@ public class MspBreakpoint implements Watchpoint {
} }
} else if (element.getName().equals("line")) { } else if (element.getName().equals("line")) {
lineNr = Integer.parseInt(element.getText()); lineNr = Integer.parseInt(element.getText());
} else if (element.getName().equals("address")) { } else if (element.getName().equals("contikicode")) {
address = Integer.parseInt(element.getText()); String lastContikiCode = element.getText().trim();
/* Verify that Contiki code did not change */
final String code = StringUtils.loadFromFile(codeFile);
if (code != null) {
String[] lines = code.split("\n");
if (lineNr-1 < lines.length) {
contikiCode = lines[lineNr-1].trim();
}
}
if (!lastContikiCode.equals(contikiCode)) {
logger.warn("Detected modified Contiki code at breakpoint: " + codeFile.getPath() + ":" + lineNr + ".");
logger.warn("From: '" + lastContikiCode + "'");
logger.warn(" To: '" + contikiCode + "'");
}
} else if (element.getName().equals("msg")) { } else if (element.getName().equals("msg")) {
msg = element.getText(); msg = element.getText();
} else if (element.getName().equals("color")) { } else if (element.getName().equals("color")) {
@ -204,51 +241,18 @@ public class MspBreakpoint implements Watchpoint {
} }
} }
if (address == null) { /* Update executable address */
address = mspMote.getExecutableAddressOf(codeFile, lineNr);
if (address < 0) {
logger.fatal("Could not restore breakpoint, did source code change?");
return false; return false;
} }
/* TODO Save source code line */
if (codeFile != null && lineNr != null) {
/* Update executable address */
address = mspMote.getBreakpointsContainer().getExecutableAddressOf(codeFile, lineNr);
if (address == null) {
logger.fatal("Could not restore breakpoint, did source code change?");
address = 0;
}
}
createMonitor(); createMonitor();
return true; return true;
} }
public void setUserMessage(String msg) { public String toString() {
this.msg = msg; return getMote() + ": " + getDescription();
} }
public String getUserMessage() {
return msg;
}
public void setColor(Color color) {
this.color = color;
}
public String getDescription() {
String desc = "";
if (codeFile != null) {
desc += codeFile.getPath() + ":" + lineNr + " (0x" + Integer.toHexString(address.intValue()) + ")";
} else if (address != null) {
desc += "0x" + Integer.toHexString(address.intValue());
}
if (msg != null) {
desc += "\n\n" + msg;
}
return desc;
}
public Color getColor() {
return color;
}
} }

View file

@ -1,280 +0,0 @@
/*
* Copyright (c) 2009, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: MspBreakpointContainer.java,v 1.3 2010/01/21 22:32:32 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.WatchpointMote;
import se.sics.cooja.mspmote.MspMote;
/**
* Breakpoint collection
*
* @author Fredrik Osterlind
*/
public class MspBreakpointContainer implements WatchpointMote {
private static Logger logger = Logger.getLogger(MspBreakpointContainer.class);
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null;
private MspMote mspMote;
private ArrayList<MspBreakpoint> breakpoints = new ArrayList<MspBreakpoint>();
private ArrayList<ActionListener> listeners = new ArrayList<ActionListener>();
private MspBreakpoint lastTriggeredBreakpoint = null;
/**
* @param debuggingInfo Debugging information read from firmware file
* @param mote Mote
*/
public MspBreakpointContainer(MspMote mote, Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo) {
this.mspMote = mote;
this.debuggingInfo = debuggingInfo;
}
/**
* Add breakpoint at given address.
*
* @param address Executable address
*/
public void addBreakpoint(Integer address) {
addBreakpoint((File) null, (Integer) null, address);
}
/**
* Add breakpoint at given address with given meta data.
*
* @param codeFile Source code file
* @param lineNr Source code file line number
* @param address Executable address
* @return Added breakpoint
*/
public MspBreakpoint addBreakpoint(File codeFile, int lineNr, Integer address) {
MspBreakpoint bp = new MspBreakpoint(this, mspMote, address, codeFile, new Integer(lineNr));
breakpoints.add(bp);
/* Notify listeners */
lastTriggeredBreakpoint = null;
for (ActionListener listener: listeners) {
listener.actionPerformed(null);
}
return bp;
}
/**
* Remove breakpoint at given address.
*
* @param address Executable address
*/
public MspBreakpoint removeBreakpoint(Integer address) {
MspBreakpoint breakpointToRemove = null;
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getExecutableAddress().intValue() == address.intValue()) {
breakpointToRemove = breakpoint;
break;
}
}
if (breakpointToRemove == null) {
return null;
}
breakpointToRemove.unregisterBreakpoint();
breakpoints.remove(breakpointToRemove);
/* Notify listeners */
lastTriggeredBreakpoint = null;
for (ActionListener listener: listeners) {
listener.actionPerformed(null);
}
return breakpointToRemove;
}
/**
* Checks if a breakpoint exists at given address.
*
* @param address Executable address
* @return True if breakpoint exists, false otherwise
*/
public boolean breakpointExists(Integer address) {
if (address == null) {
return false;
}
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getExecutableAddress().intValue() == address.intValue()) {
return true;
}
}
return false;
}
public boolean breakpointExists(File file, int lineNr) {
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getCodeFile() == null) {
continue;
}
if (breakpoint.getCodeFile().compareTo(file) != 0) {
continue;
}
if (breakpoint.getLineNumber().intValue() != lineNr) {
continue;
}
return true;
}
return false;
}
/**
* @return All breakpoints
*/
public MspBreakpoint[] getBreakpoints() {
return breakpoints.toArray(new MspBreakpoint[0]);
}
public int getBreakpointsCount() {
return breakpoints.size();
}
public void addWatchpointListener(ActionListener listener) {
listeners.add(listener);
}
public void removeWatchpointListener(ActionListener listener) {
listeners.remove(listener);
}
public ActionListener[] getWatchpointListeners() {
return listeners.toArray(new ActionListener[0]);
}
protected void signalBreakpointTrigger(MspBreakpoint b) {
if (b.stopsSimulation() && mspMote.getSimulation().isRunning()) {
/* Stop simulation immediately */
mspMote.stopNextInstruction();
}
/* Notify listeners */
lastTriggeredBreakpoint = b;
ActionListener[] arr = getWatchpointListeners();
for (ActionListener listener: arr) {
listener.actionPerformed(null);
}
}
public MspMote getMote() {
return mspMote;
}
public MspBreakpoint getLastWatchpoint() {
return lastTriggeredBreakpoint;
}
/**
* Tries to calculate the executable address of given file.
* Using debugging information from firmware file,
*
* @param file Source code file
* @param lineNr Source code file line number
* @return Executable address or null if not found
*/
public Integer getExecutableAddressOf(File file, int lineNr) {
if (file == null || lineNr < 0 || debuggingInfo == null) {
return null;
}
/* Match file */
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
if (lineTable == null) {
Enumeration<File> fileEnum = debuggingInfo.keys();
while (fileEnum.hasMoreElements()) {
File f = fileEnum.nextElement();
if (f != null && f.getName().equals(file.getName())) {
lineTable = debuggingInfo.get(f);
break;
}
}
}
if (lineTable == null) {
return null;
}
/* Match line number */
Integer address = lineTable.get(lineNr);
if (address != null) {
Enumeration<Integer> lineEnum = lineTable.keys();
while (lineEnum.hasMoreElements()) {
Integer l = lineEnum.nextElement();
if (l != null && l.intValue() == lineNr) {
/* Found line address */
return lineTable.get(l);
}
}
}
return null;
}
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
Element element;
for (MspBreakpoint breakpoint: breakpoints) {
element = new Element("breakpoint");
element.addContent(breakpoint.getConfigXML());
config.add(element);
}
return config;
}
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("breakpoint")) {
MspBreakpoint breakpoint = new MspBreakpoint(this, mspMote);
if (!breakpoint.setConfigXML(element.getChildren(), visAvailable)) {
logger.warn("Could not restore breakpoint: " + breakpoint);
} else {
breakpoints.add(breakpoint);
}
}
}
return true;
}
}