msp430 specific plugins

This commit is contained in:
fros4943 2008-02-07 14:55:18 +00:00
parent 52cacb7947
commit 749c0aa639
5 changed files with 1501 additions and 0 deletions

View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 2007, 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: BreakpointsUI.java,v 1.1 2008/02/07 14:55:18 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger;
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints;
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints.Breakpoint;
public class BreakpointsUI extends JPanel {
private static Logger logger = Logger.getLogger(BreakpointsUI.class);
private JTable breakpointsTable = null;
private Breakpoints breakpoints = null;
private AbstractTableModel tableModel = new AbstractTableModel() {
private String[] tableColumnNames = {
"Address",
"File",
"Line",
"Remove"
};
public String getColumnName(int col) { return tableColumnNames[col].toString(); }
public int getRowCount() { return breakpoints.getBreakpoints().size(); }
public int getColumnCount() { return tableColumnNames.length; }
public Object getValueAt(int row, int col) {
// Display executable address in hexadecimal
if (col == 0) {
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress();
return "0x" + Integer.toHexString(address.intValue());
}
// Display only name of file
if (col == 1) {
File file = breakpoints.getBreakpoints().get(row).getCodeFile();
if (file == null) {
return "";
}
return file.getName();
}
// Display line number
if (col == 2) {
Integer line = breakpoints.getBreakpoints().get(row).getLineNumber();
if (line == null) {
return "";
}
return line;
}
return new Boolean(false);
}
public boolean isCellEditable(int row, int col){
return getColumnClass(col) == Boolean.class;
}
public void setValueAt(Object value, int row, int col) {
fireTableCellUpdated(row, col);
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress();
breakpoints.removeBreakpoint(address);
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
};
public BreakpointsUI(Breakpoints breakpoints) {
this.breakpoints = breakpoints;
breakpoints.addBreakpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Breakpoint triggered = BreakpointsUI.this.breakpoints.getLastTriggered();
if (triggered != null) {
flashBreakpoint(triggered);
}
breakpointsTable.repaint();
}
});
breakpointsTable = new JTable(tableModel) {
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int rowIndex = breakpointsTable.rowAtPoint(p);
int colIndex = breakpointsTable.columnAtPoint(p);
int realColumnIndex = breakpointsTable.convertColumnIndexToModel(colIndex);
if (realColumnIndex == 1) {
Vector<Breakpoint> allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.size()) {
return "";
}
File file = allBreakpoints.get(rowIndex).getCodeFile();
if (file == null) {
return "";
} else {
tip = file.getPath();
}
}
return tip;
}
};
setLayout(new BorderLayout());
add(breakpointsTable.getTableHeader(), BorderLayout.PAGE_START);
add(breakpointsTable, BorderLayout.CENTER);
}
private int flashCounter = 0;
private void flashBreakpoint(Breakpoint breakpoint) {
int index = breakpoints.getBreakpoints().indexOf(breakpoint);
breakpointsTable.setRowSelectionInterval(index, index);
breakpointsTable.setSelectionBackground(Color.RED);
flashCounter = 8;
final Timer timer = new Timer(100, null);
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (flashCounter-- <= 0) {
timer.stop();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(Color.WHITE);
}
});
return;
}
// Toggle background color
if (breakpointsTable.getSelectionBackground() != Color.RED) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(Color.RED);
}
});
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(Color.WHITE);
}
});
}
}
});
timer.start();
}
}

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2007, 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: CodeUI.java,v 1.1 2008/02/07 14:55:18 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Vector;
import javax.swing.*;
import org.apache.log4j.Logger;
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints;
/**
* Displays source code and allows a user to add and remove breakpoints.
*
* @author Fredrik Österlind
*/
public class CodeUI extends JPanel {
private static Logger logger = Logger.getLogger(CodeUI.class);
private JPanel panel = null;
private JList codeList = null;
private File currentFile = null;
private Breakpoints breakpoints = null;
/**
* @param breakpoints Breakpoints
*/
public CodeUI(Breakpoints breakpoints) {
this.breakpoints = breakpoints;
setLayout(new BorderLayout());
panel = new JPanel(new BorderLayout());
add(panel, BorderLayout.CENTER);
displayNoCode();
breakpoints.addBreakpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (codeList != null) {
codeList.updateUI();
}
}
});
}
/**
* Remove any shown source code.
*/
public void displayNoCode() {
// Display "no code" message
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.removeAll();
panel.repaint();
}
});
currentFile = null;
return;
}
/**
* Display given source code and mark given line.
*
* @param codeFile Source code file
* @param codeData Source code
* @param lineNr Line numer
*/
public void displayNewCode(final File codeFile, final Vector<String> codeData, final int lineNr) {
currentFile = codeFile;
if (codeData == null || codeData.size() == 0) {
displayNoCode();
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Display code
codeList = new JList(new CodeListModel(codeData));
codeList.setFont(new Font("courier", 0, 12));
codeList.setCellRenderer(new CodeCellRenderer(lineNr));
codeList.addMouseListener(new MouseListener() {
public void mousePressed(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseReleased(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseEntered(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseExited(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseClicked(MouseEvent e) {
handleMouseEvent(e);
}
});
panel.removeAll();
panel.add(codeList);
displayLine(lineNr);
}
});
}
/**
* Mark given line number in shown source code.
*
* @param lineNumber Line number
*/
public void displayLine(final int lineNumber) {
if (codeList == null) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (lineNumber > 0) {
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
int index = lineNumber - 1;
codeList.setSelectedIndex(index);
codeList.ensureIndexIsVisible(Math.max(0, index-3));
codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize()));
codeList.ensureIndexIsVisible(index);
}
codeList.updateUI();
}
});
}
private void handleMouseEvent(MouseEvent event) {
if (event.isPopupTrigger()) {
Point menuLocation = codeList.getPopupLocation(event);
if (menuLocation == null) {
menuLocation = new Point(
codeList.getLocationOnScreen().x + event.getX(),
codeList.getLocationOnScreen().y + event.getY());
}
final int currentLine = codeList.locationToIndex(new Point(event.getX(), event.getY())) + 1;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
codeList.setSelectedIndex(currentLine - 1);
}
});
JPopupMenu popupMenu = createPopupMenu(currentFile, currentLine);
popupMenu.setLocation(menuLocation);
popupMenu.setInvoker(codeList);
popupMenu.setVisible(true);
}
}
private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) {
final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr);
boolean breakpointExists = false;
if (executableAddress != null) {
breakpointExists = breakpoints.breakpointExists(executableAddress);
}
JPopupMenu menuMotePlugins = new JPopupMenu();
JMenuItem headerMenuItem = new JMenuItem("Breakpoints:");
headerMenuItem.setEnabled(false);
menuMotePlugins.add(headerMenuItem);
menuMotePlugins.add(new JSeparator());
JMenuItem addBreakpointMenuItem = new JMenuItem("Add breakpoint on line " + lineNr);
if (executableAddress == null || breakpointExists) {
addBreakpointMenuItem.setEnabled(false);
} else {
addBreakpointMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakpoints.addBreakpoint(codeFile, lineNr, executableAddress);
}
});
}
menuMotePlugins.add(addBreakpointMenuItem);
JMenuItem delBreakpointMenuItem = new JMenuItem("Delete breakpoint on line " + lineNr);
if (executableAddress == null || !breakpointExists) {
delBreakpointMenuItem.setEnabled(false);
} else {
delBreakpointMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakpoints.removeBreakpoint(executableAddress);
}
});
}
menuMotePlugins.add(delBreakpointMenuItem);
return menuMotePlugins;
}
private class CodeListModel extends AbstractListModel {
private Vector<String> codeData;
public CodeListModel(Vector<String> codeData) {
super();
this.codeData = codeData;
}
public int getSize() {
if (codeData == null || codeData.isEmpty()) {
return 0;
}
return codeData.size();
}
public Object getElementAt(int index) {
if (codeData == null || codeData.isEmpty()) {
return "No code to display";
}
return codeData.get(index);
}
}
private class CodeCellRenderer extends JLabel implements ListCellRenderer {
private int currentIndex;
public CodeCellRenderer(int currentLineNr) {
this.currentIndex = currentLineNr - 1;
}
public void changeCurrentLine(int currentLineNr) {
this.currentIndex = currentLineNr - 1;
}
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
int lineNr = index + 1;
setText(lineNr + ": " + value);
if (index == currentIndex) {
setBackground(Color.green);
} else if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
Integer executableAddress = breakpoints.getExecutableAddressOf(currentFile, lineNr);
if (breakpoints.breakpointExists(executableAddress)) {
setFont(list.getFont().deriveFont(Font.BOLD));
} else {
setFont(list.getFont());
}
setOpaque(true);
return this;
}
}
}

View file

@ -0,0 +1,751 @@
/*
* Copyright (c) 2007, 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: MspCodeWatcher.java,v 1.1 2008/02/07 14:55:18 fros4943 Exp $
*/
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.InputStreamReader;
import java.util.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import org.apache.log4j.Logger;
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.mspsim.core.MSP430;
import se.sics.mspsim.util.DebugUI;
import se.sics.mspsim.util.Utils;
@ClassDescription("Msp Code Watcher")
@PluginType(PluginType.MOTE_PLUGIN)
public class MspCodeWatcher extends VisPlugin {
private static Logger logger = Logger.getLogger(MspCodeWatcher.class);
private Simulation mySimulation;
private Observer simObserver;
private MspMote mspMote;
private MspMoteType moteType;
private JButton stepButton;
private File codeFile = null;
private int lineNumber = -1;
private DebugUI instructionsUI;
private CodeUI codeUI;
private BreakpointsUI breakpointsUI;
private Breakpoints breakpoints = null;
private JLabel filenameLabel;
/**
* Mini-debugger for MSP Motes.
* Visualizes instructions, source code and allows a user to manipulate breakpoints.
*
* @param mote MSP Mote
* @param simulationToVisualize Simulation
* @param gui Simulator
*/
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<File, Hashtable<Integer, Integer>> debuggingInfo = getFirmwareDebugInfo();
breakpoints = new Breakpoints(debuggingInfo, mspMote);
getContentPane().setLayout(new BorderLayout());
instructionsUI = new DebugUI(this.mspMote.getCPU(), true);
breakpointsUI = new BreakpointsUI(breakpoints);
codeUI = new CodeUI(breakpoints);
JSplitPane leftPanel = 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)
);
JPanel controlPanel = new JPanel();
// Extract files found in debugging info
final Vector<File> files = new Vector<File>();
Enumeration fileEnum = debuggingInfo.keys();
while (fileEnum.hasMoreElements()) {
File file = (File) fileEnum.nextElement();
// Insert file on correct position
int index = 0;
for (index=0; index < files.size(); index++) {
if (file.getName().compareToIgnoreCase(files.get(index).getName()) < 0) {
break;
}
}
files.add(index, file);
}
String[] fileNames = new String[files.size() + 1];
fileNames[0] = "[select file]";
for (int i=0; i < files.size(); i++) {
fileNames[i+1] = files.get(i).getName();
}
JComboBox fileComboBox = new JComboBox(fileNames);
fileComboBox.setSelectedIndex(0);
fileComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox source = (JComboBox)e.getSource();
int index = source.getSelectedIndex();
if (index == 0) {
return;
}
File selectedFile = files.get(index-1);
Vector<String> codeData = readTextFile(selectedFile);
codeUI.displayNewCode(selectedFile, codeData, -1);
codeFile = null;
}
});
fileComboBox.setRenderer(new BasicComboBoxRenderer() {
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
if (index > 0) {
list.setToolTipText(files.get(index-1).getPath());
}
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setFont(list.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
});
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
topPanel.add(BorderLayout.EAST, fileComboBox);
topPanel.add(BorderLayout.CENTER, filenameLabel = new JLabel(""));
// Add single step button
stepButton = new JButton("Single step");
stepButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO Perform single step here
mspMote.getCPU().step();
updateInfo();
}
});
controlPanel.add(stepButton);
add(BorderLayout.CENTER, new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
leftPanel,
new JScrollPane(codeUI)
));
add(BorderLayout.SOUTH, controlPanel);
add(BorderLayout.NORTH, topPanel);
// Register as tickobserver
mySimulation.addObserver(simObserver = new Observer() {
public void update(Observable obs, Object obj) {
if (!mySimulation.isRunning()) {
stepButton.setEnabled(true);
updateInfo();
} else {
stepButton.setEnabled(false);
}
}
});
setSize(350, 250);
pack();
// Tries to select this plugin
try {
setSelected(true);
} catch (java.beans.PropertyVetoException e) {
// Could not select
}
}
/**
* Contains currently active breakpoints.
*
* @author Fredrik Österlind
*/
static class Breakpoints {
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null;
private Vector<Breakpoint> breakpoints = new Vector<Breakpoint>();
private Vector<ActionListener> listeners = new Vector<ActionListener>();
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<File, Hashtable<Integer, Integer>> debuggingInfo, MspMote mote) {
this.debuggingInfo = debuggingInfo;
this.mspMote = mote;
}
/**
* @param debuggingInfo Debugging information read from firmware file
* @param mote MspMote
*/
public Breakpoints(Hashtable<File, Hashtable<Integer, Integer>> 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<Breakpoint> 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 Österlind
*/
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<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
Element element;
element = new Element("address");
element.setText(address.toString());
config.add(element);
if (codeFile != null) {
element = new Element("codefile");
element.setText(codeFile.getAbsolutePath());
config.add(element);
}
if (lineNr != null) {
element = new Element("line");
element.setText(lineNr.toString());
config.add(element);
}
return config;
}
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("codefile")) {
codeFile = new File(element.getText());
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<Integer, Integer> 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<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
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<Element> 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();
// Try locate source file
File oldCodeFile = codeFile;
updateCurrentSourceCodeFile();
// If found and not already loaded, load source file
if (oldCodeFile == null || !oldCodeFile.getPath().equals(codeFile.getPath())) {
Vector<String> codeData = readTextFile(codeFile);
codeUI.displayNewCode(codeFile, codeData, lineNumber);
} else {
codeUI.displayLine(lineNumber);
}
codeUI.repaint();
if (codeFile != null) {
filenameLabel.setText(codeFile.getName() + ":" + lineNumber);
} else {
filenameLabel.setText("");
}
}
public void closePlugin() {
mySimulation.deleteObserver(simObserver);
while (breakpoints.getBreakpoints().size() > 0) {
breakpoints.removeBreakpoint(breakpoints.getBreakpoints().firstElement().getExecutableAddress());
}
}
private void updateCurrentSourceCodeFile() {
codeFile = null;
try {
String[] cmd = new String[]{
"addr2line",
"-e",
moteType.getELFFile().getPath(),
Utils.hex16(mspMote.getCPU().reg[MSP430.PC])
};
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader input =
new BufferedReader(
new InputStreamReader(
p.getInputStream()));
String output = input.readLine();
input.close();
if (output == null || output.startsWith("?")) {
return;
}
String[] fileInfo = output.split(":");
if (fileInfo.length != 2) {
return;
}
// TODO Ugly Cygwin-Windows support
fileInfo[0] = fileInfo[0].replace("/cygdrive/c/", "c:/");
codeFile = new File(fileInfo[0]);
lineNumber = Integer.parseInt(fileInfo[1]);
} catch (Exception e) {
logger.fatal("Error while calling addr2line: " + e);
codeFile = null;
lineNumber = -1;
}
}
private Hashtable<File, Hashtable<Integer, Integer>> getFirmwareDebugInfo() {
return getFirmwareDebugInfo(moteType.getELFFile());
}
/**
* Tries to read debugging information from firmware file using objdump.
*
* @return Hashtable with debugging information
*/
public static Hashtable<File, Hashtable<Integer, Integer>> getFirmwareDebugInfo(File firmware) {
Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo =
new Hashtable<File, Hashtable<Integer, Integer>>();
Hashtable<Integer, Integer> currentHashtable = null;
try {
String[] cmd = new String[]{
"objdump",
"-g",
firmware.getPath()
};
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader input =
new BufferedReader(
new InputStreamReader(
p.getInputStream()));
String line = null;
while ((line = input.readLine()) != null) {
line = line.trim();
/* Check for new source file */
if (line.endsWith(":")) {
String fileName = line.substring(0, line.length()-1);
fileName = fileName.replace("/cygdrive/c/", "c:/");
currentHashtable = null;
// Try path unchanged
File file = new File(fileName);
if (currentHashtable == null && file.exists()) {
currentHashtable = new Hashtable<Integer, Integer>();
debuggingInfo.put(file, currentHashtable);
}
// Try adding firmwarepath
file = new File(firmware.getParent(), fileName);
if (currentHashtable == null && file.exists()) {
currentHashtable = new Hashtable<Integer, Integer>();
debuggingInfo.put(file, currentHashtable);
}
if (currentHashtable == null) { // TODO Currently always true
logger.warn("Can't locate file: " + fileName);
}
}
/* Check for source file line info */
if (currentHashtable != null && line.startsWith("/* file ")) {
String[] lineInfo = line.split(" ");
String lineNrString = lineInfo[lineInfo.length-4];
String addressString = lineInfo[lineInfo.length-2];
int lineNr = Integer.parseInt(lineNrString);
int address = Integer.parseInt(addressString.substring(2), 16);
currentHashtable.put(new Integer(lineNr), new Integer(address));
}
}
input.close();
} catch (Exception e) {
logger.fatal("Error while calling objdump: " + e);
}
return debuggingInfo;
}
/**
* Tries to open and read given text file.
*
* @param textFile File
* @return Line-by-line text in file
*/
public static Vector<String> readTextFile(File textFile) {
try {
BufferedReader in =
new BufferedReader(
new FileReader(textFile));
String line;
Vector<String> textData = new Vector<String>();
while ((line = in.readLine()) != null) {
textData.add(line);
}
in.close();
return textData;
} catch (Exception e) {
return null;
}
}
public Collection<Element> getConfigXML() {
return breakpoints.getConfigXML();
}
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
return breakpoints.setConfigXML(configXML, visAvailable);
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2007, 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: MspCycleWatcher.java,v 1.1 2008/02/07 14:55:18 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import javax.swing.*;
import org.apache.log4j.Logger;
import se.sics.cooja.*;
import se.sics.cooja.mspmote.MspMote;
import se.sics.mspsim.core.MSP430;
@ClassDescription("Msp Cycle Watcher")
@PluginType(PluginType.MOTE_PLUGIN)
public class MspCycleWatcher extends VisPlugin {
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
private MspMote mspMote;
private MSP430 cpu;
private Simulation simulation;
private Observer simObserver = null;
private JTextField cycleTextField = new JTextField("");
private JTextField resetTextField = new JTextField("");
private long cycleReset = 0;
public MspCycleWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
super("Msp Cycle Watcher", gui);
this.mspMote = (MspMote) mote;
cpu = mspMote.getCPU();
simulation = simulationToVisualize;
cycleTextField.setEditable(false);
resetTextField.setEditable(false);
getContentPane().setLayout(new BorderLayout());
JButton updateButton = new JButton("Update");
updateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateLabels();
}
});
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cycleReset = cpu.cycles;
updateLabels();
}
});
JPanel controlPanel = new JPanel(new GridLayout(2,3,5,5));
controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
controlPanel.add(new JLabel("Total cycles:"));
controlPanel.add(cycleTextField);
controlPanel.add(updateButton);
controlPanel.add(new JLabel("Since reset:"));
controlPanel.add(resetTextField);
controlPanel.add(resetButton);
add(BorderLayout.CENTER, controlPanel);
setSize(370, 100);
simulation.addObserver(simObserver = new Observer() {
public void update(Observable obs, Object obj) {
updateLabels();
}
});
updateLabels();
// Tries to select this plugin
try {
setSelected(true);
} catch (java.beans.PropertyVetoException e) {
// Could not select
}
}
private void updateLabels() {
cycleTextField.setText("" + cpu.cycles);
resetTextField.setText("" + (cpu.cycles - cycleReset));
}
public void closePlugin() {
simulation.deleteObserver(simObserver);
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2007, 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: MspStackWatcher.java,v 1.1 2008/02/07 14:55:18 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import org.apache.log4j.Logger;
import se.sics.cooja.*;
import se.sics.cooja.mspmote.MspMote;
import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.util.StackUI;
import se.sics.mspsim.util.Utils;
@ClassDescription("Msp Stack Watcher")
@PluginType(PluginType.MOTE_PLUGIN)
public class MspStackWatcher extends VisPlugin {
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
private MspMote mspMote;
private MSP430 cpu;
private Simulation simulation;
private Observer stackObserver = null;
private Observer logObserver = null;
private JButton startButton;
private JButton stopButton;
public MspStackWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
super("Msp Stack Watcher", gui);
this.mspMote = (MspMote) mote;
cpu = mspMote.getCPU();
simulation = simulationToVisualize;
getContentPane().setLayout(new BorderLayout());
// Register as stack observable
if (stackObserver == null) {
mspMote.getStackOverflowObservable().addObserver(stackObserver = new Observer() {
public void update(Observable obs, Object obj) {
simulation.stopSimulation();
JOptionPane.showMessageDialog(
MspStackWatcher.this,
"Bad memory access!\nSimulation stopped.\n" +
"\nCurrent stack pointer = 0x" + Utils.hex16(cpu.reg[MSP430.SP]) +
"\nStart of heap = 0x" + Utils.hex16(cpu.getDisAsm().getMap().heapStartAddress),
"Stack overflow", JOptionPane.ERROR_MESSAGE
);
}
});
}
// Create stack overflow controls
startButton = new JButton("Stop simulation on stack overflow");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
mspMote.monitorStack(true);
}
});
stopButton = new JButton("Cancel");
stopButton.setEnabled(false);
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
mspMote.monitorStack(false);
}
});
// Create nfi's stack viewer
final StackUI stackUI = new StackUI(cpu, MspMote.NR_CYCLES_PER_MSEC);
// Register as log listener
if (logObserver == null && mspMote.getInterfaces().getLog() != null) {
mspMote.getInterfaces().getLog().addObserver(logObserver = new Observer() {
public void update(Observable obs, Object obj) {
stackUI.addNote(mspMote.getInterfaces().getLog().getLastLogMessages());
}
});
}
JPanel controlPanel = new JPanel(new GridLayout(2,1));
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(BorderLayout.CENTER, stackUI);
add(BorderLayout.SOUTH, controlPanel);
setSize(240, 300);
// Tries to select this plugin
try {
setSelected(true);
} catch (java.beans.PropertyVetoException e) {
// Could not select
}
}
public void closePlugin() {
mspMote.getStackOverflowObservable().deleteObserver(stackObserver);
}
}