📄 mspcodewatcher.java
字号:
/* * 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.14 2008/11/03 18:11:44 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.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;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.core.MSP430Core;import se.sics.mspsim.ui.DebugUI;import se.sics.mspsim.util.DebugInfo;@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 currentCodeFile = null; private int currentLineNumber = -1; private DebugUI instructionsUI; private CodeUI codeUI; private BreakpointsUI breakpointsUI; private Breakpoints breakpoints = null; private JButton currentFileButton; private Vector<File> sourceFilesAlpha; private JComboBox fileComboBox; /** * 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); breakpoints.addBreakpointListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateInfo(); } }); 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(); /* Create source file list */ File[] sourceFiles = getAllSourceFileNames(); sourceFilesAlpha = new Vector<File>(); 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); } 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.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) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); if (index > 0) { list.setToolTipText(sourceFilesAlpha.get(index-1).getPath()); } } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } setFont(list.getFont()); setText((value == null) ? "" : value.toString()); return this; } }); currentFileButton = new JButton("[unknown]"); currentFileButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (currentCodeFile == null) { return; } displaySourceFile(currentCodeFile, currentLineNumber); } }); JPanel topPanel = new JPanel(); topPanel.setLayout(new BorderLayout()); topPanel.add(BorderLayout.EAST, fileComboBox); 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 mspMote.getCPU().step(mspMote.getCPU().cycles+1); 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; } 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; } } } logger.fatal("Function '" + functionName + "' did not return within " + max + " instructions"); updateInfo(); } }); controlPanel.add(stepButton); JSplitPane splitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(codeUI), rightPanel); splitPane.setOneTouchExpandable(true); splitPane.setResizeWeight(0.8); add(BorderLayout.CENTER, splitPane); 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(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); return; } logger.info("Reading source file " + file); Vector<String> codeData = readTextFile(file); lastReadTextFile = file; codeUI.displayNewCode(file, codeData, line); } private void sourceFileSelectionChanged() { int index = fileComboBox.getSelectedIndex(); if (index == 0) { return; } File selectedFile = sourceFilesAlpha.get(index-1); displaySourceFile(selectedFile, -1); } /** * Contains currently active breakpoints. * * @author Fredrik Osterlind */ 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -