diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java index 22e69309c..fec21997b 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: MspCodeWatcher.java,v 1.16 2009/03/12 17:47:57 fros4943 Exp $ + * $Id: MspCodeWatcher.java,v 1.17 2009/06/11 10:12:44 fros4943 Exp $ */ package se.sics.cooja.mspmote.plugins; @@ -34,15 +34,12 @@ package se.sics.cooja.mspmote.plugins; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.*; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLConnection; import java.util.*; + import javax.swing.*; import javax.swing.plaf.basic.BasicComboBoxRenderer; import org.apache.log4j.Logger; @@ -50,8 +47,7 @@ import org.jdom.Element; import se.sics.cooja.*; import se.sics.cooja.mspmote.MspMote; -import se.sics.cooja.mspmote.MspMoteType; -import se.sics.mspsim.core.CPUMonitor; +import se.sics.cooja.util.StringUtils; import se.sics.mspsim.core.EmulationException; import se.sics.mspsim.core.MSP430; import se.sics.mspsim.core.MSP430Core; @@ -62,26 +58,23 @@ import se.sics.mspsim.util.DebugInfo; @PluginType(PluginType.MOTE_PLUGIN) public class MspCodeWatcher extends VisPlugin { private static Logger logger = Logger.getLogger(MspCodeWatcher.class); - private Simulation mySimulation; + private Simulation simulation; private Observer simObserver; private MspMote mspMote; - private MspMoteType moteType; - private JButton stepButton; private File currentCodeFile = null; private int currentLineNumber = -1; - private DebugUI instructionsUI; - private CodeUI codeUI; + private JSplitPane leftSplitPane, rightSplitPane; + private DebugUI assCodeUI; + private CodeUI sourceCodeUI; private BreakpointsUI breakpointsUI; - private Breakpoints breakpoints = null; + private MspBreakpointContainer breakpoints = null; - private JButton currentFileButton; - - private Vector sourceFilesAlpha; private JComboBox fileComboBox; - + private final File[] sourceFiles; + /** * Mini-debugger for MSP Motes. * Visualizes instructions, source code and allows a user to manipulate breakpoints. @@ -93,59 +86,27 @@ public class MspCodeWatcher extends VisPlugin { public MspCodeWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) { super("Msp Code Watcher", gui); this.mspMote = (MspMote) mote; - this.moteType = (MspMoteType) mote.getType(); - mySimulation = simulationToVisualize; - - Hashtable> debuggingInfo = getFirmwareDebugInfo(); - breakpoints = new Breakpoints(debuggingInfo, mspMote); - breakpoints.addBreakpointListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - updateInfo(); - } - }); + simulation = simulationToVisualize; getContentPane().setLayout(new BorderLayout()); - instructionsUI = new DebugUI(this.mspMote.getCPU(), true); - breakpointsUI = new BreakpointsUI(breakpoints, this); - codeUI = new CodeUI(breakpoints); - - JSplitPane rightPanel = new JSplitPane( - JSplitPane.VERTICAL_SPLIT, - new JScrollPane(instructionsUI, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), - new JScrollPane(breakpointsUI, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED) - ); - rightPanel.setOneTouchExpandable(true); - rightPanel.setResizeWeight(0.2); - - JPanel controlPanel = new JPanel(); - + /* Breakpoints */ + breakpoints = mspMote.getBreakpointsContainer(); + /* Create source file list */ - File[] sourceFiles = getAllSourceFileNames(); - sourceFilesAlpha = new Vector(); - for (File file: sourceFiles) { - /* Insert files alphabetically */ - int index = 0; - for (index=0; index < sourceFilesAlpha.size(); index++) { - if (file.getName().compareToIgnoreCase(sourceFilesAlpha.get(index).getName()) < 0) { - break; - } - } - sourceFilesAlpha.add(index, file); + sourceFiles = getSourceFiles(mspMote); + String[] sourceFilesHeader = new String[sourceFiles.length + 1]; + sourceFilesHeader[0] = "[view sourcefile]"; + for (int i=0; i < sourceFiles.length; i++) { + sourceFilesHeader[i+1] = sourceFiles[i].getName(); } - String[] sourceFilesAlphaArray = new String[sourceFilesAlpha.size() + 1]; - sourceFilesAlphaArray[0] = "[view sourcefile]"; - for (int i=0; i < sourceFilesAlpha.size(); i++) { - sourceFilesAlphaArray[i+1] = sourceFilesAlpha.get(i).getName(); - } - fileComboBox = new JComboBox(sourceFilesAlphaArray); + fileComboBox = new JComboBox(sourceFilesHeader); fileComboBox.setSelectedIndex(0); fileComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { sourceFileSelectionChanged(); } }); - fileComboBox.setRenderer(new BasicComboBoxRenderer() { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -153,7 +114,7 @@ public class MspCodeWatcher extends VisPlugin { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); if (index > 0) { - list.setToolTipText(sourceFilesAlpha.get(index-1).getPath()); + list.setToolTipText(sourceFiles[index-1].getPath()); } } else { setBackground(list.getBackground()); @@ -165,142 +126,85 @@ public class MspCodeWatcher extends VisPlugin { } }); - currentFileButton = new JButton("[unknown]"); - currentFileButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (currentCodeFile == null) { - return; - } + + /* Browse code control (north) */ + JButton currentFileButton = new JButton(currentFileAction); - displaySourceFile(currentCodeFile, currentLineNumber); - } - }); + Box browseBox = Box.createHorizontalBox(); + browseBox.add(Box.createHorizontalStrut(10)); + browseBox.add(new JLabel("Program counter: ")); + browseBox.add(currentFileButton); + browseBox.add(Box.createHorizontalGlue()); + browseBox.add(new JLabel("Browse: ")); + browseBox.add(fileComboBox); + browseBox.add(Box.createHorizontalStrut(10)); - JPanel topPanel = new JPanel(); - topPanel.setLayout(new BorderLayout()); - topPanel.add(BorderLayout.EAST, fileComboBox); + + /* Execution control panel (south) */ + JPanel controlPanel = new JPanel(); + JButton button = new JButton(stepAction); + stepAction.putValue(Action.NAME, "Step instruction"); + controlPanel.add(button); + button = new JButton(untilAction); + untilAction.putValue(Action.NAME, "Until function return"); + /*controlPanel.add(button);*/ - JPanel currentFilePanel = new JPanel(); - currentFilePanel.add(BorderLayout.WEST, new JLabel("current file:")); - currentFilePanel.add(BorderLayout.WEST, currentFileButton); - topPanel.add(BorderLayout.WEST, currentFilePanel); - - - /* Instruction button */ - stepButton = new JButton("Single instruction"); - stepButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - // TODO Perform single step here - try { - mspMote.getCPU().step(mspMote.getCPU().cycles+1); - } catch (EmulationException e1) { - logger.fatal("Error: ", e1); - } - updateInfo(); - } - }); - controlPanel.add(stepButton); - - /* Return button */ - stepButton = new JButton("Until function returns"); - stepButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - /* XXX Experimental */ - final int max = 10000; - int count=0; - int pc, instruction; - MSP430 cpu = mspMote.getCPU(); - int depth = 0; - - /* Extract function name */ - DebugInfo debugInfo = mspMote.getELF().getDebugInfo(mspMote.getCPU().reg[MSP430.PC]); - if (debugInfo == null || debugInfo.getFunction() == null) { - logger.fatal("Unknown function"); - return; - } - String functionName = debugInfo.getFunction().split(":")[0]; - logger.info("Function: '" + functionName + "'"); - - pc = cpu.readRegister(MSP430Core.PC); - instruction = cpu.memory[pc] + (cpu.memory[pc + 1] << 8); - if (instruction == MSP430.RETURN) { - logger.fatal("Already at return instruction"); - return; - } - - try { - while (count++ < max) { - cpu.step(mspMote.getCPU().cycles+1); - pc = cpu.readRegister(MSP430Core.PC); - instruction = cpu.memory[pc] + (cpu.memory[pc + 1] << 8); - if ((instruction & 0xff80) == MSP430.CALL) { - depth++; - } else if (instruction == MSP430.RETURN) { - depth--; - if (depth < 0) { - updateInfo(); - return; - } - - } - } - } catch (EmulationException e1) { - logger.fatal("Error: ", e1); - } - - logger.fatal("Function '" + functionName + "' did not return within " + max + " instructions"); - updateInfo(); - } - }); - controlPanel.add(stepButton); - - JSplitPane splitPane = new JSplitPane( + + /* Main components: assembler and C code + breakpoints (center) */ + assCodeUI = new DebugUI(this.mspMote.getCPU(), true); + breakpointsUI = new BreakpointsUI(breakpoints, this); + sourceCodeUI = new CodeUI(breakpoints); + leftSplitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, - new JScrollPane(codeUI), - rightPanel); - splitPane.setOneTouchExpandable(true); - splitPane.setResizeWeight(0.8); - - add(BorderLayout.CENTER, splitPane); + new JScrollPane(assCodeUI), + new JScrollPane(breakpointsUI) + ); + leftSplitPane.setOneTouchExpandable(true); + leftSplitPane.setDividerLocation(0.0); + rightSplitPane = new JSplitPane( + JSplitPane.HORIZONTAL_SPLIT, + leftSplitPane, + new JScrollPane(sourceCodeUI) + ); + rightSplitPane.setOneTouchExpandable(true); + rightSplitPane.setDividerLocation(0.0); + add(BorderLayout.NORTH, browseBox); + add(BorderLayout.CENTER, rightSplitPane); add(BorderLayout.SOUTH, controlPanel); - add(BorderLayout.NORTH, topPanel); - // Register as tickobserver - mySimulation.addObserver(simObserver = new Observer() { + + /* Observe when simulation starts/stops */ + simulation.addObserver(simObserver = new Observer() { public void update(Observable obs, Object obj) { - if (!mySimulation.isRunning()) { - stepButton.setEnabled(true); + if (!simulation.isRunning()) { + stepAction.setEnabled(true); + untilAction.setEnabled(true); updateInfo(); } else { - stepButton.setEnabled(false); + stepAction.setEnabled(false); + untilAction.setEnabled(false); } } }); setSize(750, 500); updateInfo(); - - // Tries to select this plugin - try { - setSelected(true); - } catch (java.beans.PropertyVetoException e) { - // Could not select - } } - private File lastReadTextFile = null; public void displaySourceFile(File file, int line) { - - if (lastReadTextFile != null && file.compareTo(lastReadTextFile) == 0) { - codeUI.displayLine(line); + if (file != null && + sourceCodeUI.displayedFile != null && + file.compareTo(sourceCodeUI.displayedFile) == 0) { + sourceCodeUI.displayLine(line); return; } - - logger.info("Reading source file " + file); - Vector codeData = readTextFile(file); - lastReadTextFile = file; - codeUI.displayNewCode(file, codeData, line); + logger.info("Reading source file: " + file); + String[] codeData = readTextFile(file); + if (codeData == null) { + return; + } + sourceCodeUI.displayNewCode(file, codeData, line); } private void sourceFileSelectionChanged() { @@ -309,391 +213,38 @@ public class MspCodeWatcher extends VisPlugin { return; } - File selectedFile = sourceFilesAlpha.get(index-1); + File selectedFile = sourceFiles[index-1]; displaySourceFile(selectedFile, -1); } - /** - * Contains currently active breakpoints. - * - * @author Fredrik Osterlind - */ - class Breakpoints { - private Hashtable> debuggingInfo = null; - private Vector breakpoints = new Vector(); - private Vector listeners = new Vector(); - private Breakpoint lastBreakpoint = null; - private MspMote mspMote = null; - private boolean stopOnBreakpointTriggered = true; - - /** - * @param debuggingInfo Debugging information read from firmware file - * @param mote MspMote - */ - public Breakpoints(Hashtable> debuggingInfo, MspMote mote) { - this.debuggingInfo = debuggingInfo; - this.mspMote = mote; - } - - /** - * @param debuggingInfo Debugging information read from firmware file - * @param mote MspMote - */ - public Breakpoints(Hashtable> debuggingInfo, MspMote mote, boolean stopOnBreakpointTriggered) { - this(debuggingInfo, mote); - this.stopOnBreakpointTriggered = stopOnBreakpointTriggered; - } - - /** - * 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 Breakpoint addBreakpoint(File codeFile, int lineNr, Integer address) { - Breakpoint bp = new Breakpoint(codeFile, new Integer(lineNr), address, mspMote); - breakpoints.add(bp); - lastBreakpoint = null; - for (ActionListener listener: listeners) { - listener.actionPerformed(null); - } - return bp; - } - - /** - * Remove breakpoint at given address. - * - * @param address Executable address - */ - public void removeBreakpoint(Integer address) { - Breakpoint breakpointToRemove = null; - for (Breakpoint breakpoint: breakpoints) { - if (breakpoint.getExecutableAddress().intValue() == address.intValue()) { - breakpointToRemove = breakpoint; - break; - } - } - if (breakpointToRemove == null) { - return; - } - - breakpointToRemove.unregisterBreakpoint(); - breakpoints.remove(breakpointToRemove); - - // Notify listeners - lastBreakpoint = null; - for (ActionListener listener: listeners) { - listener.actionPerformed(null); - } - } - - /** - * 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 (Breakpoint breakpoint: breakpoints) { - if (breakpoint.getExecutableAddress().intValue() == address.intValue()) { - return true; - } - } - return false; - } - - /** - * @return All breakpoints - */ - public Vector getBreakpoints() { - return breakpoints; - } - - /** - * Adds a breakpoint listener. - * The listener will be notified when breakpoints are added are removed. - * - * @param listener Breakpoint listener - */ - public void addBreakpointListener(ActionListener listener) { - listeners.add(listener); - } - - private void breakpointReached(Breakpoint b) { - if (stopOnBreakpointTriggered) { - mspMote.getSimulation().stopSimulation(); - mspMote.stopNextInstruction(); - } - - // Notify listeners - lastBreakpoint = b; - for (ActionListener listener: listeners) { - listener.actionPerformed(null); - } - } - - public MspMote getMote() { - return mspMote; - } - - public Breakpoint getLastTriggered() { - return lastBreakpoint; - } - - /** - * Breakpoint wrapper class. - * May contain breakpoint meta data such source code file and line number. - * - * @author Fredrik Osterlind - */ - class Breakpoint { - private CPUMonitor cpuMonitor = null; - private File codeFile = null; - private Integer lineNr = null; - private Integer address = null; - private MspMote mspMote = null; - - /** - * Create new uninitialized breakpoint. Used with setConfigXML(). - */ - public Breakpoint(MspMote mote) { - this.mspMote = mote; - } - - /** - * Creates new breakpoint wrapper at given address. - * - * @param address Executable address - * @param mote MSP mote - */ - public Breakpoint(Integer address, MspMote mote) { - this.mspMote = mote; - - cpuMonitor = new CPUMonitor() { - public void cpuAction(int type, int adr, int data) { - breakpointReached(Breakpoint.this); - } - }; - - mspMote.getCPU().setBreakPoint(address, cpuMonitor); - this.address = address; - } - - /** - * Creates new breakpoint wrapper at given address with given meta data. - * - * @param codeFile Source code file - * @param lineNr Source code file line number - * @param address Executable address - * @param mote MSP mote - */ - public Breakpoint(File codeFile, Integer lineNr, Integer address, MspMote mote) { - this(address, mote); - this.codeFile = codeFile; - this.lineNr = lineNr; - } - - /** - * @return MSP mote - */ - public MspMote getMote() { - return mspMote; - } - - /** - * @return Source code file - */ - public File getCodeFile() { - return codeFile; - } - - /** - * @return Source code file line number - */ - public Integer getLineNumber() { - return lineNr; - } - - /** - * @return Executable address - */ - public Integer getExecutableAddress() { - return address; - } - - private 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); - - if (codeFile != null) { - element = new Element("codefile"); - File file = mySimulation.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) { - for (Element element : configXML) { - if (element.getName().equals("codefile")) { - File file = new File(element.getText()); - if (!file.exists()) { - file = mySimulation.getGUI().restorePortablePath(file); - } - codeFile = file; - if (!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()); - } - } - - if (address == null) { - return false; - } - - cpuMonitor = new CPUMonitor() { - public void cpuAction(int type, int adr, int data) { - breakpointReached(Breakpoint.this); - } - }; - - mspMote.getCPU().setBreakPoint(address, cpuMonitor); - return true; - } - } - - /** - * Tries to, using debugging information from firmware file, calculate the executable address of given meta data. - * - * @param codeFile Source code file - * @param lineNr Source code file line number - * @return Executable address or null if not found - */ - public Integer getExecutableAddressOf(File codeFile, int lineNr) { - if (codeFile == null || lineNr < 0) { - return null; - } - - // Match file names - Enumeration fileEnum = debuggingInfo.keys(); - while (fileEnum.hasMoreElements()) { - File file = (File) fileEnum.nextElement(); - if (file != null && file.getName().equals(codeFile.getName())) { - /* Found source code file */ - Hashtable lineTable = debuggingInfo.get(file); - Enumeration lineEnum = lineTable.keys(); - while (lineEnum.hasMoreElements()) { - Integer line = (Integer) lineEnum.nextElement(); - if (line != null && line.intValue() == lineNr) { - /* Found line address */ - return lineTable.get(line); - } - } - // TODO Return null here to only allow unique source files - } - } - return null; - } - - public Collection getConfigXML() { - Vector config = new Vector(); - Element element; - - for (Breakpoint breakpoint: breakpoints) { - element = new Element("breakpoint"); - - Collection breakpointXML = breakpoint.getConfigXML(); - if (breakpointXML != null) { - element.addContent(breakpointXML); - config.add(element); - } - } - - return config; - } - - public boolean setConfigXML(Collection configXML, boolean visAvailable) { - for (Element element : configXML) { - if (element.getName().equals("breakpoint")) { - Breakpoint breakpoint = new Breakpoint(mspMote); - boolean ret = breakpoint.setConfigXML(element.getChildren(), visAvailable); - if (!ret) { - return false; - } - - breakpoints.add(breakpoint); - lastBreakpoint = null; - } - } - return true; - } - - } - private void updateInfo() { // Update instructions view - instructionsUI.updateRegs(); - instructionsUI.repaint(); + assCodeUI.updateRegs(); + assCodeUI.repaint(); // Try locate source file updateCurrentSourceCodeFile(); if (currentCodeFile == null) { + currentFileAction.setEnabled(false); + currentFileAction.putValue(Action.NAME, "[unknown]"); return; } + displaySourceFile(currentCodeFile, currentLineNumber); - codeUI.repaint(); - - if (currentCodeFile != null) { - currentFileButton.setText(currentCodeFile.getName() + ":" + currentLineNumber); - } else { - currentFileButton.setText("[unknown]"); - } + currentFileAction.setEnabled(true); + currentFileAction.putValue(Action.NAME, currentCodeFile.getName() + ":" + currentLineNumber); fileComboBox.setSelectedIndex(0); - } + } public void closePlugin() { - mySimulation.deleteObserver(simObserver); - while (breakpoints.getBreakpoints().size() > 0) { - breakpoints.removeBreakpoint(breakpoints.getBreakpoints().firstElement().getExecutableAddress()); + simulation.deleteObserver(simObserver); + + /* Delete breakpoints */ + while (breakpoints.getBreakpoints().length > 0) { + breakpoints.removeBreakpoint(breakpoints.getBreakpoints()[0].getExecutableAddress()); } - } private void updateCurrentSourceCodeFile() { @@ -721,8 +272,9 @@ public class MspCodeWatcher extends VisPlugin { } currentCodeFile = new File(path, debugInfo.getFile()); + currentCodeFile = currentCodeFile.getCanonicalFile(); + currentLineNumber = debugInfo.getLine(); - } catch (Exception e) { logger.fatal("Exception: " + e); currentCodeFile = null; @@ -730,10 +282,16 @@ public class MspCodeWatcher extends VisPlugin { } } - private File[] getAllSourceFileNames() { - String[] sourceFiles = mspMote.getELF().getDebug().getSourceFiles(); - Vector files = new Vector(); - + private static File[] getSourceFiles(MspMote mote) { + String[] sourceFiles = mote.getELF().getDebug().getSourceFiles(); + File contikiSource = mote.getType().getContikiSourceFile(); + try { + contikiSource = contikiSource.getCanonicalFile(); + } catch (IOException e1) { + } + + /* Verify that files exist */ + Vector existing = new Vector(); for (String sourceFile: sourceFiles) { /* Nasty Cygwin-Windows fix */ if (sourceFile.contains("/cygdrive/")) { @@ -743,94 +301,53 @@ public class MspCodeWatcher extends VisPlugin { } File file = new File(sourceFile); + try { + file = file.getCanonicalFile(); + } catch (IOException e1) { + } if (!GUI.isVisualizedInApplet()) { - if (!file.exists() || !file.isFile()) { - logger.warn("Can't locate source file, skipping: " + file.getPath()); + if (file.exists() && file.isFile()) { + existing.add(file); } else { - files.add(file); + /*logger.warn("Can't locate source file, skipping: " + file.getPath());*/ } } else { /* Accept all files without existence check */ - files.add(file); + existing.add(file); } } - File[] filesArray = new File[files.size()]; - for (int i=0; i < filesArray.length; i++) { - filesArray[i] = files.get(i); - } - - return filesArray; - } - - private Hashtable> getFirmwareDebugInfo() { - - /* Fetch all executable addresses */ - ArrayList addresses = mspMote.getELF().getDebug().getExecutableAddresses(); - - Hashtable> fileToLineHash = - new Hashtable>(); - - for (int address: addresses) { - DebugInfo info = mspMote.getELF().getDebugInfo(address); - - if (info != null && info.getPath() != null && info.getFile() != null && info.getLine() >= 0) { - - /* Nasty Cygwin-Windows fix */ - String path = info.getPath(); - if (path.contains("/cygdrive/")) { - int index = path.indexOf("/cygdrive/"); - char driveCharacter = path.charAt(index+10); - - path = path.replace("/cygdrive/" + driveCharacter + "/", driveCharacter + ":/"); + /* Sort alphabetically */ + Vector sorted = new Vector(); + for (File file: existing) { + int index = 0; + for (index=0; index < sorted.size(); index++) { + if (file.getName().compareToIgnoreCase(sorted.get(index).getName()) < 0) { + break; } - - File file = new File(path, info.getFile()); - - Hashtable lineToAddrHash = fileToLineHash.get(file); - if (lineToAddrHash == null) { - lineToAddrHash = new Hashtable(); - fileToLineHash.put(file, lineToAddrHash); - } - - lineToAddrHash.put(info.getLine(), address); } + sorted.add(index, file); + } + + /* Add Contiki source first */ + if (contikiSource != null && contikiSource.exists()) { + sorted.add(0, contikiSource); } - return fileToLineHash; + File[] sortedArr = sorted.toArray(new File[0]); + return sortedArr; } /** * Tries to open and read given text file. * - * @param textFile File + * @param file File * @return Line-by-line text in file */ - public static Vector readTextFile(URL textFile) throws IOException { - URLConnection urlConnection = textFile.openConnection(); - urlConnection.setDoInput(true); - urlConnection.setUseCaches(false); - - Vector data = new Vector(); - BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - data.add(line); - } - - return data; - } - - /** - * Tries to open and read given text file. - * - * @param textFile File - * @return Line-by-line text in file - */ - public static Vector readTextFile(File textFile) { + public static String[] readTextFile(File file) { if (GUI.isVisualizedInApplet()) { /* Download from web server instead */ - String path = textFile.getPath(); + String path = file.getPath(); /* Extract Contiki build path */ String contikiBuildPath = GUI.getExternalToolsSetting("PATH_CONTIKI_BUILD"); @@ -845,7 +362,8 @@ public class MspCodeWatcher extends VisPlugin { path = contikiWebPath + '/' + path.substring(contikiBuildPath.length()); path = path.replace('\\', '/'); URL url = new URL(GUI.getAppletCodeBase(), path); - return readTextFile(url); + String data = StringUtils.loadFromURL(url); + return data!=null?data.split("\n"):null; } catch (MalformedURLException e) { logger.warn("Failure to read source code: " + e); return null; @@ -855,33 +373,110 @@ public class MspCodeWatcher extends VisPlugin { } } - try { - BufferedReader in = - new BufferedReader( - new FileReader(textFile)); - - String line; - Vector textData = new Vector(); - while ((line = in.readLine()) != null) { - textData.add(line); - } - - in.close(); - - return textData; - - } catch (Exception e) { - return null; - } + String data = StringUtils.loadFromFile(file); + return data!=null?data.split("\n"):null; } public Collection getConfigXML() { - return breakpoints.getConfigXML(); + Vector config = new Vector(); + Element element; + + element = new Element("breakpoints"); + element.addContent(breakpoints.getConfigXML()); + config.add(element); + + element = new Element("split_1"); + element.addContent("" + leftSplitPane.getDividerLocation()); + config.add(element); + + element = new Element("split_2"); + element.addContent("" + rightSplitPane.getDividerLocation()); + config.add(element); + + return config; } public boolean setConfigXML(Collection configXML, boolean visAvailable) { - return breakpoints.setConfigXML(configXML, visAvailable); + for (Element element : configXML) { + if (element.getName().equals("breakpoints")) { + breakpoints.setConfigXML(element.getChildren(), visAvailable); + } else if (element.getName().equals("split_1")) { + leftSplitPane.setDividerLocation(Integer.parseInt(element.getText())); + } else if (element.getName().equals("split_2")) { + rightSplitPane.setDividerLocation(Integer.parseInt(element.getText())); + } + } + return true; } + private AbstractAction currentFileAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + if (currentCodeFile == null) { + return; + } + displaySourceFile(currentCodeFile, currentLineNumber); + } + }; + + private AbstractAction stepAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + try { + mspMote.getCPU().step(mspMote.getCPU().cycles+1); + } catch (EmulationException ex) { + logger.fatal("Error: ", ex); + } + updateInfo(); + } + }; + + private AbstractAction untilAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + /* XXX TODO Implement me */ + final int max = 10000; + int count=0; + int pc, instruction; + MSP430 cpu = mspMote.getCPU(); + int depth = 0; + + /* Extract function name */ + DebugInfo debugInfo = mspMote.getELF().getDebugInfo(mspMote.getCPU().reg[MSP430.PC]); + if (debugInfo == null || debugInfo.getFunction() == null) { + logger.fatal("Unknown function"); + return; + } + String functionName = debugInfo.getFunction().split(":")[0]; + logger.info("Function: '" + functionName + "'"); + + pc = cpu.readRegister(MSP430Core.PC); + instruction = cpu.memory[pc] + (cpu.memory[pc + 1] << 8); + if (instruction == MSP430.RETURN) { + logger.fatal("Already at return instruction"); + return; + } + + try { + while (count++ < max) { + cpu.step(mspMote.getCPU().cycles+1); + pc = cpu.readRegister(MSP430Core.PC); + instruction = cpu.memory[pc] + (cpu.memory[pc + 1] << 8); + if ((instruction & 0xff80) == MSP430.CALL) { + depth++; + } else if (instruction == MSP430.RETURN) { + depth--; + if (depth < 0) { + updateInfo(); + return; + } + + } + } + } catch (EmulationException e1) { + logger.fatal("Error: ", e1); + } + + logger.fatal("Function '" + functionName + "' did not return within " + max + " instructions"); + updateInfo(); + } + }; }