/******************************************************************************* * Copyright (c) 2000, 2009 QNX Software Systems and others. * All rights reserved. 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 * * Contributors: * QNX Software Systems - Initial API and implementation * Ericsson AB - Modified for new DSF Reference Implementation * Ericsson AB - Reverted to byte[] and processed multi-line results *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service.command.output; import java.math.BigInteger; import org.eclipse.debug.core.model.MemoryByte; /** * * -data-read-memory result * * (gdb) * nn-data-read-memory [command parameters] * nn^done,addr="ADDRESS",nr-bytes="NR_BYTES",total-bytes="TOTAL_BYTES", * next-row="NEXT_ROW",prev-row="PREV_ROW",next-page="NEXT_PAGE", * prev-page="PREV_PAGE",memory=[ * {addr="addr1",data=["0x00","0x01", ...]}, * {addr="addr2",data=["0x02","0x03", ...]}, * {addr="addr3",data=["0x04","0x05", ...]}, * ...] * (gdb) * * where: * * 'ADDRESS' * Address (in hex) of the first byte fetched. * * 'NR_BYTES' * Number of bytes read. * * 'TOTAL_BYTES' * Number of bytes requested (nr-rows * nr-columns * word-size). * * 'NEXT_ROW' * Address (in hex) of the next row. * * 'PREV_ROW' * Address (in hex) of the previous row. * * 'NEXT_PAGE' * Address (in hex) of the next page. * * 'PREV_PAGE' * Address (in hex) of the previous page. * * 'MEMORY' * Memory bytes retrieved, nr-rows of nr-columns words. * */ public class MIDataReadMemoryInfo extends MIInfo { // The parsed values of interest BigInteger fAddress = new BigInteger("0"); //$NON-NLS-1$ int fBytesRead; int fBytesRequested; MemoryByte[] fMemoryBlock; /** * Constructor * * @param output */ public MIDataReadMemoryInfo(MIOutput output) { super(output); fMemoryBlock = new MemoryByte[0]; if (isDone()) { parseResult(1); } } /** * Constructor * * @param output */ public MIDataReadMemoryInfo(MIOutput output, int word_size) { super(output); fMemoryBlock = new MemoryByte[0]; if (isDone()) { parseResult(word_size); } } /** * Parse the back-end-result. The result is an array of the following form: * * [0] addr="address" * [1] nr-bytes="x" * [2] total-bytes="y" * [3] next-row="address2" * [4] prev-row="address3" * [5] next-page="address4" * [6] prev-page="address5" * [7] memory=[{addr="addr1",data=["0x00","0x01",...]}] * * At this point, we only have interest in "memory". */ private void parseResult(int word_size) { // Get the GDB/MI result record MIOutput output = getMIOutput(); MIResultRecord record = output.getMIResultRecord(); // Parse the result record if (record != null) { // Parse the output results // Note: we assume that the result respects the output format // i.e. nothing missing, nothing out of order. MIResult[] results = record.getMIResults(); for (int i = 0; i < results.length; i++) { // Get the variable name String var = results[i].getVariable(); // Parse 'addr="address"', the address of the first byte to read if (var.equals("addr")) { //$NON-NLS-1$ MIValue value = results[i].getMIValue(); if (value instanceof MIConst) { String address = ((MIConst) value).getCString(); fAddress = new BigInteger(address.substring(2), 16); // Strip the "0x" } } // Parse 'nr-bytes="x"', the number of bytes read if (var.equals("total-bytes")) { //$NON-NLS-1$ MIValue value = results[i].getMIValue(); if (value instanceof MIConst) { String size = ((MIConst) value).getCString(); fBytesRead = Integer.parseInt(size); } } // Parse '"total-bytes="y"', the number of bytes requested // Instantiate the corresponding output buffer with invalid bytes if (var.equals("total-bytes")) { //$NON-NLS-1$ MIValue value = results[i].getMIValue(); if (value instanceof MIConst) { String size = ((MIConst) value).getCString(); fBytesRequested = Integer.parseInt(size); fMemoryBlock = new MemoryByte[fBytesRequested]; for (int j = 0; j < fMemoryBlock.length; j++) fMemoryBlock[j] = new MemoryByte((byte) 0, (byte) 0); } } // Parse 'memory=[{addr="addr1",data=["0x00","0x01",...]}]' if (var.equals("memory")) { //$NON-NLS-1$ MIValue value = results[i].getMIValue(); if (value instanceof MIList) { parseMemoryLines((MIList) value, word_size); } } } } } /** * Parse the actual memory lines of the general form: * * [{addr="addr1",data=["0x00","0x01",...]}] * [{addr="addr2",data=["0x00","0x01",...]}] * * Since we haven't implemented coalescing yet, we conveniently simplify * the processing by assuming that the memory block address matches the * one of the request. Therefore, we only have to fill the memoryBlock[] * with the incoming bytes. * * This will have to be revisited as soon as we start considering * multiple (and possibly canceled) requests. */ private void parseMemoryLines(MIList lines, int word_size) { // Parse each line and append the results to the result block MIValue[] lineValues = lines.getMIValues(); for (int i = 0; i < lineValues.length; i++) { // Each line has 2 tuples: "addr" and "data" if (lineValues[i] instanceof MITuple) { MITuple tuple = (MITuple) lineValues[i]; MIResult[] results = tuple.getMIResults(); // The offset of this particular output line in the result buffer int offset = 0; // The 1st tuple ('addr="addr1"') gives us the address of the first byte read MIValue addrValue = results[0].getMIValue(); if (addrValue instanceof MIConst) { String address = ((MIConst) addrValue).getCString(); BigInteger startAddress = new BigInteger(address.substring(2), 16); // Strip the "0x" offset = startAddress.subtract(fAddress).intValue(); } // The 2nd tuple ("data=[...]") gives us the actual bytes MIValue value = results[1].getMIValue(); if (value instanceof MIList) { MIList list = (MIList) value; MIValue[] values = list.getMIValues(); MemoryByte[] byteValues = new MemoryByte[values.length * word_size]; // Parse the result array for (int j = 0; j < values.length; j++) { if (values[j] instanceof MIConst) { String str = ((MIConst) values[j]).getCString(); try { long word = Long.decode(str.trim()).longValue(); for (int k = 0; k < word_size; k++) { int bit_shift = (word_size - k - 1) * 8; byteValues[j * word_size + k] = new MemoryByte((byte) ((word >> bit_shift) % 256)); } } catch (NumberFormatException e) { for (int k = 0; k < word_size; k++) byteValues[j * word_size + k] = new MemoryByte((byte) -1, (byte) 0); } } } // Copy the parsed line to the memory block System.arraycopy(byteValues, 0, fMemoryBlock, offset, byteValues.length); } } } } /** * Return the memory block */ public MemoryByte[] getMIMemoryBlock() { return fMemoryBlock; } }