blob: 3f5ae19dc9105c167751d18abfe2051c3ac2f261 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly marked,
* so as not to confuse it with the version available from LANL.
*
* Additionally, this program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* LA-CC 04-115
*******************************************************************************/
package org.eclipse.ptp.debug.external.core.cdi.model;
import java.math.BigInteger;
import org.eclipse.ptp.debug.core.ExtFormat;
import org.eclipse.ptp.debug.core.PDebugUtils;
import org.eclipse.ptp.debug.core.cdi.PCDIException;
import org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock;
import org.eclipse.ptp.debug.external.core.cdi.MemoryManager;
import org.eclipse.ptp.debug.external.core.cdi.Session;
import org.eclipse.ptp.debug.external.core.commands.DataWriteMemoryCommand;
/**
* @author Clement chu
*
*/
public class MemoryBlock extends PObject implements IPCDIMemoryBlock {
String expression;
boolean frozen;
boolean dirty;
private DataReadMemoryInfo mem;
private int fWordSize;
private BigInteger cStartAddress; //cached start address
private byte[] cBytes; //cached bytes
private int[] badOffsets;
private boolean fIsLittleEndian;
/** Constructor
* @param target
* @param exp
* @param wordSize
* @param isLittle
* @param info
*/
public MemoryBlock(Target target, String exp, int wordSize, boolean isLittle, DataReadMemoryInfo info) {
super(target);
expression = exp;
fWordSize = wordSize;
frozen = true;
fIsLittleEndian = isLittle;
setDataReadMemoryInfo(info);
}
/**
* @return the expression use to create the block.
*/
public String getExpression() {
return expression;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#getWordSize()
* @return the size of each memory word in bytes.
*/
public int getWordSize() {
return fWordSize;
}
/**
* Reset the internal DataReadMemoryInfo. All modifications into mem info should be don using this method
* @param m
*/
public void setDataReadMemoryInfo(DataReadMemoryInfo m) {
cStartAddress = ExtFormat.getBigInteger(m.getAddress());
cBytes = getBytes(m);
mem = m;
}
/**
* @return the internal DataReadMemoryInfo.
*/
public DataReadMemoryInfo getDataReadMemoryInfo() {
return mem;
}
/**
* @param adds
* @return true if any address in the array is within the block.
*/
public boolean contains(BigInteger[] adds) {
for (int i = 0; i < adds.length; i++) {
if (contains(adds[i])) {
return true;
}
}
return false;
}
/**
* @param addr
* @return true if the address is within the block.
*/
public boolean contains(BigInteger addr) {
BigInteger start = getStartAddress();
long length = getLength();
if ( start.compareTo(addr) <= 0 && addr.compareTo(start.add(BigInteger.valueOf(length))) <= 0 ) {
return true;
}
return false;
}
/**
* Use by the EventManager to check fire events when doing refresh().
* @return
*/
public boolean isDirty() {
return dirty;
}
/**
* Use by the EventManager to check fire events when doing refresh().
* @param d
*/
public void setDirty(boolean d) {
dirty = d;
}
/**
* @param m
* @return
*/
private byte[] getBytes(DataReadMemoryInfo m) {
byte[] bytes = new byte[0];
// sanity.
if (m == null) {
return bytes;
}
// collect the data
Memory[] miMem = m.getMemories();
for (int i = 0; i < miMem.length; ++i) {
long[] data = miMem[i].getData();
if (data != null && data.length > 0) {
// int blen = bytes.length;
// byte[] newBytes = new byte[blen + data.length];
// System.arraycopy(bytes, 0, newBytes, 0, blen);
// for (int j = 0; j < data.length; ++j, ++blen) {
// newBytes[blen] = (byte)data[j];
// }
// bytes = newBytes;
for (int j = 0; j < data.length; ++j) {
byte[] bs = longToBytes(data[j]);
// grow the array
int blen = bytes.length;
byte[] newBytes = new byte[blen + bs.length];
System.arraycopy(bytes, 0, newBytes, 0, blen);
System.arraycopy(bs, 0, newBytes, blen, bs.length);
bytes = newBytes;
}
}
}
return bytes;
}
private int[] getBadOffsets(DataReadMemoryInfo m) {
int[] offsets = new int[0];
// sanity
if (m == null) {
return offsets;
}
// collect the data
Memory[] miMem = m.getMemories();
for (int i = 0; i < miMem.length; i++) {
int[] data = miMem[i].getBadOffsets();
if (data.length > 0) {
int olen = offsets.length;
int[] newOffsets = new int[olen + data.length];
System.arraycopy(offsets, 0, newOffsets, 0, olen);
System.arraycopy(data, 0, newOffsets, olen, data.length);
offsets = newOffsets;
}
}
return offsets;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#getBytes()
*/
public byte[] getBytes() throws PCDIException {
return cBytes;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#refresh()
*/
public void refresh() throws PCDIException {
Target target = (Target)getTarget();
MemoryManager mgr = ((Session)target.getSession()).getMemoryManager();
setDirty(true);
BigInteger[] addresses = mgr.update(this, null);
// Check if this affects other blocks.
if (addresses.length > 0) {
IPCDIMemoryBlock[] blocks = mgr.getMemoryBlocks(target);
for (int i = 0; i < blocks.length; i++) {
MemoryBlock block = (MemoryBlock)blocks[i];
if (! block.equals(this) && block.contains(addresses)) {
block.setDirty(true);
mgr.update(block, null);
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#getLength()
*/
public long getLength() {
try {
// use this instead. If the wordSize
// given does not match the hardware,
// counting the bytes will be correct.
return getBytes().length;
} catch (PCDIException e) {
// ignore.
}
return mem.getTotalBytes();
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#getStartAddress()
*/
public BigInteger getStartAddress() {
return cStartAddress;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#isFrozen()
*/
public boolean isFrozen() {
return frozen;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#setFrozen(boolean)
*/
public void setFrozen(boolean frozen) {
this.frozen = frozen;
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#setValue(long, byte[])
*/
public void setValue(long offset, byte[] bytes) throws PCDIException {
if (offset >= getLength() || offset + bytes.length > getLength()) {
throw new PCDIException("No bad offset found");
}
Target target = (Target)getTarget();
for (int i = 0; i < bytes.length; i++) {
long l = new Byte(bytes[i]).longValue() & 0xff;
String value = "0x" + Long.toHexString(l);
PDebugUtils.println("----------- DataWriteMemoryCommand is called --------------");
DataWriteMemoryCommand command = new DataWriteMemoryCommand(target.getTask(), offset + i, expression, ExtFormat.HEXADECIMAL, 1, value);
target.getDebugger().postCommand(command);
if (command.getDataWriteMemoryInfo() == null) {
throw new PCDIException("No response");
}
}
// If the assign was succesfull fire a MIChangedEvent() via refresh.
refresh();
}
/* (non-Javadoc)
* @see org.eclipse.ptp.debug.core.cdi.model.IPCDIMemoryBlock#getFlags(int)
*/
public synchronized byte getFlags(int offset) {
if (offset < 0 || offset >= getLength()) {
throw new IndexOutOfBoundsException();
}
if (badOffsets == null) {
badOffsets = getBadOffsets(mem);
}
if (badOffsets != null) {
for (int i = 0; i < badOffsets.length; ++i) {
if (badOffsets[i] == offset) {
return 0;
}
}
}
return VALID;
}
/**
* We should use the wordSize ... but ...
* The problem: the user may not have the right wordsize
* For example on some DSP the user set the wordSize to be 1 byte
* but in fact GDB is reading 2 bytes.
* So let do some guessing since the data(long) may have a bigger value then one byte.
*/
private byte[] longToBytes(long v) {
// Calculate the number of bytes needed
int count = 1;
long value = v;
for (count = 1; (value /= 0x100) > 0; ++count)
;
// Reset the wordSize if incorrect.
if (fWordSize != count) {
fWordSize = count;
}
byte[] bytes = new byte[count];
if (fIsLittleEndian) {
for (int i = count - 1; i >= 0; --i) {
int shift = i * count;
bytes[i] = (byte)((v >>> shift) & 0xFF);
}
// bytes[7] = (byte)((v >>> 56) & 0xFF);
// bytes[6] = (byte)((v >>> 48) & 0xFF);
// bytes[5] = (byte)((v >>> 40) & 0xFF);
// bytes[4] = (byte)((v >>> 32) & 0xFF);
// bytes[3] = (byte)((v >>> 24) & 0xFF);
// bytes[2] = (byte)((v >>> 16) & 0xFF);
// bytes[1] = (byte)((v >>> 8) & 0xFF);
// bytes[0] = (byte)((v >>> 0) & 0xFF);
} else {
for (int i = 0; i < count; ++i) {
int shift = (count - i - 1) * count;
bytes[i] = (byte)((v >>> shift) & 0xFF);
}
// bytes[0] = (byte)((v >>> 56) & 0xFF);
// bytes[1] = (byte)((v >>> 48) & 0xFF);
// bytes[2] = (byte)((v >>> 40) & 0xFF);
// bytes[3] = (byte)((v >>> 32) & 0xFF);
// bytes[4] = (byte)((v >>> 24) & 0xFF);
// bytes[5] = (byte)((v >>> 16) & 0xFF);
// bytes[6] = (byte)((v >>> 8) & 0xFF);
// bytes[7] = (byte)((v >>> 0) & 0xFF);
}
return bytes;
}
}