From c19c8a16adee9411e9ec00c0a3b40c27fd2778dc Mon Sep 17 00:00:00 2001 From: fros4943 Date: Thu, 11 Jun 2009 10:05:28 +0000 Subject: [PATCH] mspsim breakpoint wrapper with source code information (part of the code was extracted from the code watcher plugin) --- .../cooja/mspmote/plugins/MspBreakpoint.java | 200 +++++++++++++ .../plugins/MspBreakpointContainer.java | 280 ++++++++++++++++++ 2 files changed, 480 insertions(+) create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java create 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/plugins/MspBreakpoint.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java new file mode 100644 index 000000000..16714ff40 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java @@ -0,0 +1,200 @@ +/* + * 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: MspBreakpoint.java,v 1.1 2009/06/11 10:05:28 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote.plugins; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Vector; + +import org.jdom.Element; + +import se.sics.cooja.Watchpoint; +import se.sics.cooja.mspmote.MspMote; +import se.sics.mspsim.core.CPUMonitor; + +/** + * Breakpoint. + * Contains meta data such source code file and line number. + * + * @author Fredrik Osterlind + */ +public class MspBreakpoint implements Watchpoint { + private MspBreakpointContainer breakpoints; + private MspMote mspMote; + + 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 */ + + public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote) { + this.breakpoints = breakpoints; + this.mspMote = mote; + + } + + public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address) { + this(breakpoints, mote); + this.address = address; + + 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; + } + + /** + * @return Source code file + */ + public File getCodeFile() { + return codeFile; + } + + /** + * @return Source code file line number + */ + public Integer getLineNumber() { + return lineNr; + } + + public boolean stopsSimulation() { + return stopsSimulation; + } + + public void setStopsSimulation(boolean stops) { + stopsSimulation = stops; + } + + private void createMonitor() { + cpuMonitor = new CPUMonitor() { + public void cpuAction(int type, int adr, int data) { + breakpoints.signalBreakpointTrigger(MspBreakpoint.this); + } + }; + mspMote.getCPU().setBreakPoint(address, cpuMonitor); + } + + public void unregisterBreakpoint() { + mspMote.getCPU().setBreakPoint(address, null); + } + + public Collection getConfigXML() { + Vector config = new Vector(); + 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); + } + + if (lineNr != null) { + element = new Element("line"); + element.setText(lineNr.toString()); + config.add(element); + } + + return config; + } + + 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()); + file = mspMote.getSimulation().getGUI().restorePortablePath(file); + + try { + codeFile = file.getCanonicalFile(); + } catch (IOException e) { + } + + if (codeFile == null || !codeFile.exists()) { + return false; + } + } 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("stops")) { + stopsSimulation = Boolean.parseBoolean(element.getText()); + } + } + + if (address == null) { + return false; + } + + createMonitor(); + return true; + } + + + public String getDescription() { + if (codeFile != null) { + return codeFile.getPath() + ":" + lineNr + " (0x" + Integer.toHexString(address.intValue()) + ")"; + } + return "0x" + Integer.toHexString(address.intValue()); + } +} 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 new file mode 100644 index 000000000..46c853007 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java @@ -0,0 +1,280 @@ +/* + * 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.1 2009/06/11 10:05:28 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.getSimulation().stopSimulation(); + mspMote.stopNextInstruction(); + } + + /* Notify listeners */ + lastTriggeredBreakpoint = b; + for (ActionListener listener: listeners) { + 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; + } +}