From 2e583c733ebd3402277eebe900e313b4881558e2 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 21 Mar 2012 16:57:04 +0100 Subject: [PATCH] mspsim motes now implements new WatchpointMote interface, simplified code --- .../src/se/sics/cooja/mspmote/ESBMote.java | 4 +- .../src/se/sics/cooja/mspmote/MspMote.java | 230 ++++++++++---- .../cooja/mspmote/plugins/MspBreakpoint.java | 200 +++++++------ .../plugins/MspBreakpointContainer.java | 280 ------------------ 4 files changed, 274 insertions(+), 440 deletions(-) delete mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java index c3e5475e5..8c4fb6608 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java @@ -32,10 +32,10 @@ package se.sics.cooja.mspmote; import java.io.File; + import org.apache.log4j.Logger; -import se.sics.cooja.MoteInterfaceHandler; + import se.sics.cooja.Simulation; -import se.sics.cooja.interfaces.*; import se.sics.mspsim.platform.esb.ESBNode; /** diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java index d2d2e154f..ecc77fafa 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java @@ -31,12 +31,13 @@ package se.sics.cooja.mspmote; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; import java.util.Observable; 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.mspmote.interfaces.MspSerial; import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin; -import se.sics.cooja.mspmote.plugins.MspBreakpointContainer; -import se.sics.cooja.plugins.BufferListener.BufferAccess; +import se.sics.cooja.mspmote.plugins.MspBreakpoint; import se.sics.cooja.plugins.Visualizer; import se.sics.mspsim.cli.CommandContext; import se.sics.mspsim.cli.CommandHandler; import se.sics.mspsim.cli.LineListener; import se.sics.mspsim.cli.LineOutputStream; -import se.sics.mspsim.core.CPUMonitor; import se.sics.mspsim.core.EmulationException; import se.sics.mspsim.core.MSP430; import se.sics.mspsim.core.MSP430Constants; @@ -95,7 +94,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc private MspMoteMemory myMemory = null; private MoteInterfaceHandler myMoteInterfaceHandler = null; public ComponentRegistry registry = null; - + /* Stack monitoring variables */ private boolean stopNextInstruction = false; private boolean monitorStackUsage = false; @@ -103,15 +102,11 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc private int heapStartAddress; private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable(); - private MspBreakpointContainer breakpointsContainer; - public MspMote() { myMoteType = null; myCpu = null; myMemory = null; myMoteInterfaceHandler = null; - - /* Scheduled from setConfigXML */ } public MspMote(MspMoteType moteType, Simulation simulation) { @@ -121,7 +116,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* Schedule us immediately */ requestImmediateWakeup(); } - + protected void initMote() { if (myMoteType != null) { initEmulator(myMoteType.getContikiFirmwareFile()); @@ -130,9 +125,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* TODO Setup COOJA-specific window manager */ registry.registerComponent("windowManager", new JFrameWindowManager()); - /* Create watchpoint container */ try { - breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo()); + debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo(); } catch (IOException e) { throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e); } @@ -300,10 +294,9 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc if (stopNextInstruction) { stopNextInstruction = false; - /*sendCLICommandAndPrint("trace 1000");*/ /* TODO Enable */ scheduleNextWakeup(t); throw new RuntimeException("MSPSim requested simulation stop"); - } + } if (lastExecute < 0) { /* Always execute one microsecond the first time */ @@ -312,12 +305,12 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc if (t < lastExecute) { throw new RuntimeException("Bad event ordering: " + lastExecute + " < " + t); } - + /* Execute MSPSim-based mote */ /* TODO Try-catch overhead */ try { - nextExecute = - t + duration + + nextExecute = + t + duration + myCpu.stepMicros(t - lastExecute, duration); lastExecute = t; } catch (EmulationException e) { @@ -332,8 +325,12 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } /*logger.debug(t + ": Schedule next wakeup at " + nextExecute);*/ scheduleNextWakeup(nextExecute); - - + + if (stopNextInstruction) { + stopNextInstruction = false; + throw new RuntimeException("MSPSim requested simulation stop"); + } + /* XXX TODO Reimplement stack monitoring using MSPSim internals */ /*if (monitorStackUsage) { int newStack = cpu.reg[MSP430.SP]; @@ -349,7 +346,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } }*/ } - + public String getStackTrace() { return executeCLICommand("stacktrace"); } @@ -357,7 +354,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc public int executeCLICommand(String cmd, CommandContext context) { return commandHandler.executeCommand(cmd, context); } - + public String executeCLICommand(String cmd) { final StringBuilder sb = new StringBuilder(); LineListener ll = new LineListener() { @@ -369,14 +366,14 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc CommandContext c = new CommandContext(commandHandler, null, "", new String[0], 1, null); c.out = po; c.err = po; - + if (0 != executeCLICommand(cmd, c)) { sb.append("\nWarning: command failed"); } - + return sb.toString(); } - + public int getCPUFrequency() { return myCpu.getDCOFrequency(); } @@ -384,16 +381,15 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc public int getID() { return getInterfaces().getMoteID().getMoteID(); } - + public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) { setSimulation(simulation); if (myMoteInterfaceHandler == null) { myMoteInterfaceHandler = createMoteInterfaceHandler(); } - /* Create watchpoint container */ try { - breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo()); + debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo(); } catch (IOException 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")) { /* Ignored: handled by simulation */ } else if ("breakpoints".equals(element.getName())) { - breakpointsContainer.setConfigXML(element.getChildren(), visAvailable); + setWatchpointConfigXML(element.getChildren(), visAvailable); } else if (name.equals("interface_config")) { String intfClass = element.getText().trim(); if (intfClass.equals("se.sics.cooja.mspmote.interfaces.MspIPAddress")) { @@ -440,7 +436,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* Breakpoints */ element = new Element("breakpoints"); - element.addContent(breakpointsContainer.getConfigXML()); + element.addContent(getWatchpointConfigXML()); config.add(element); // Mote interfaces @@ -458,41 +454,15 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc 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() { return executeCLICommand("stacktrace"); } public String getPCString() { int pc = myCpu.getPC(); - ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class); + ELF elf = myCpu.getRegistry().getComponent(ELF.class); DebugInfo di = elf.getDebugInfo(pc); - + /* Following code examples from MSPsim, DebugCommands.java */ if (di == null) { di = elf.getDebugInfo(pc + 1); @@ -510,7 +480,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } } String name = mapEntry.getName(); - return file + ":?:" + name; + return file + ":?:" + name; } return String.format("*%02x", myCpu.reg[MSP430Constants.PC]); } catch (Exception e) { @@ -525,7 +495,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* strip path */ file = file.substring(file.lastIndexOf('/')+1, file.length()); } - + String function = di.getFunction(); function = function==null?"":function; if (function.contains(":")) { @@ -536,7 +506,147 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc function = "?"; } return file + ":" + lineNo + ":" + function; - + /*return executeCLICommand("line " + myCpu.getPC());*/ } + + + /* WatchpointMote */ + private ArrayList watchpointListeners = new ArrayList(); + private ArrayList watchpoints = new ArrayList(); + private Hashtable> 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 lineTable = debuggingInfo.get(file); + if (lineTable == null) { + Enumeration 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 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 getWatchpointConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + for (MspBreakpoint breakpoint: watchpoints) { + element = new Element("breakpoint"); + element.addContent(breakpoint.getConfigXML()); + config.add(element); + } + + return config; + } + public boolean setWatchpointConfigXML(Collection 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; + } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java index 7f2c18a81..e6d881e97 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java @@ -34,129 +34,151 @@ package se.sics.cooja.mspmote.plugins; import java.awt.Color; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; -import java.util.Vector; import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.Watchpoint; import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.util.StringUtils; import se.sics.mspsim.core.CPUMonitor; /** - * Breakpoint. - * Contains meta data such source code file and line number. + * Mspsim watchpoint. * * @author Fredrik Osterlind */ public class MspBreakpoint implements Watchpoint { private static Logger logger = Logger.getLogger(MspBreakpoint.class); - private MspBreakpointContainer breakpoints; 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 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 Color color = Color.BLACK; - public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote) { - this.breakpoints = breakpoints; + private String contikiCode = null; + + public MspBreakpoint(MspMote mote) { this.mspMote = mote; + /* expects setConfigXML(..) */ } - public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address) { - this(breakpoints, mote); + public MspBreakpoint(MspMote mote, Integer address, File codeFile, Integer lineNr) { + this(mote); this.address = address; + this.codeFile = codeFile; + this.lineNr = lineNr; 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() { return mspMote; } - /** - * @return Executable address - */ - public Integer getExecutableAddress() { - return address; + public Color getColor() { + return color; } - - /** - * @return Source code file - */ + public void setColor(Color color) { + 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; + } + public File getCodeFile() { return codeFile; } - - /** - * @return Source code file line number - */ - public Integer getLineNumber() { + public int getLineNumber() { return lineNr; } - - public boolean stopsSimulation() { - return stopsSimulation; + public int getExecutableAddress() { + return address; } public void setStopsSimulation(boolean stops) { stopsSimulation = stops; } + public boolean stopsSimulation() { + return stopsSimulation; + } private void createMonitor() { cpuMonitor = new CPUMonitor() { 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); + + + /* 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() { mspMote.getCPU().removeWatchPoint(address, cpuMonitor); } public Collection getConfigXML() { - Vector config = new Vector(); + ArrayList config = new ArrayList(); Element element; - element = new Element("address"); - element.setText(address.toString()); - config.add(element); - element = new Element("stops"); element.setText("" + stopsSimulation); config.add(element); - if (codeFile != null) { - element = new Element("codefile"); - File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile); - element.setText(file.getPath().replaceAll("\\\\", "/")); - config.add(element); - } + element = new Element("codefile"); + File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile); + element.setText(file.getPath().replaceAll("\\\\", "/")); + config.add(element); - if (lineNr != null) { - element = new Element("line"); - element.setText(lineNr.toString()); + element = new Element("line"); + element.setText("" + lineNr); + config.add(element); + + if (contikiCode != null) { + element = new Element("contikicode"); + element.setText(contikiCode); config.add(element); } @@ -177,7 +199,7 @@ public class MspBreakpoint implements Watchpoint { public boolean setConfigXML(Collection configXML, boolean visAvailable) { /* Already knows mote and breakpoints */ - + for (Element element : configXML) { if (element.getName().equals("codefile")) { File file = new File(element.getText()); @@ -193,8 +215,23 @@ public class MspBreakpoint implements Watchpoint { } } else if (element.getName().equals("line")) { lineNr = Integer.parseInt(element.getText()); - } else if (element.getName().equals("address")) { - address = Integer.parseInt(element.getText()); + } else if (element.getName().equals("contikicode")) { + 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")) { msg = element.getText(); } 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; } - - /* 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(); + return true; } - public void setUserMessage(String msg) { - this.msg = msg; + public String toString() { + 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; - } - } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java deleted file mode 100644 index 27c721615..000000000 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java +++ /dev/null @@ -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> debuggingInfo = null; - private MspMote mspMote; - - private ArrayList breakpoints = new ArrayList(); - private ArrayList listeners = new ArrayList(); - private MspBreakpoint lastTriggeredBreakpoint = null; - - /** - * @param debuggingInfo Debugging information read from firmware file - * @param mote Mote - */ - public MspBreakpointContainer(MspMote mote, Hashtable> 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 lineTable = debuggingInfo.get(file); - if (lineTable == null) { - Enumeration 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 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 getConfigXML() { - Vector config = new Vector(); - Element element; - - for (MspBreakpoint breakpoint: breakpoints) { - element = new Element("breakpoint"); - element.addContent(breakpoint.getConfigXML()); - config.add(element); - } - - return config; - } - - public boolean setConfigXML(Collection 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; - } -}