blob: c83ad2397f564693fc7b651e73e2cc7c144a992d [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008 Texas Instruments 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:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== Decoder.java ========
*/
package xdc.rta;
import xdc.rov.TargetDecoder;
import xdc.rov.TargetEncoder;
/*
* ======== Decoder ========
* This class decodes xdc.runtime.Log.Event records from raw target bytes.
* The records are decoded into HostEvent objects from which the event message
* can be retrieved.
*
* The Decoder requires a MetaData object to provide information about the
* target used for decoding the raw bytes, as well as for retrieving the
* mapping of event ids to messages. See xdc.rta.MetaData.
*
*/
public class Decoder
{
private TargetDecoder targDecoder;
private TargetEncoder targEncoder;
private MetaData meta = null;
/*
* ======== Decoder ========
* If the Decoder is constructed with a MetaData instance, then it is
* initialized and ready to go.
*/
public Decoder(MetaData meta)
{
init(meta);
}
/*
* ======== Decoder ========
* No-argument constructor.
*
* If the Decoder is constructed with no arguments, it must be initialized
* using one of the 'parse' APIs before decoding any records.
*/
public Decoder()
{
}
/*
* ======== init ========
* Initializes the decoder for use. The Decoder can be initialized by
* either passing a MetaData instance to the constructor or by using one
* of the parse APIs. This API contains the common initialization code.
*/
private void init(MetaData meta)
{
this.meta = meta;
/*
* Create the underlying target decoder and encoder for working with
* target bytes.
*/
targDecoder = new TargetDecoder(meta.getEndianess(),
meta.getBitsPerChar());
targEncoder = new TargetEncoder(meta.getEndianess(),
meta.getBitsPerChar());
}
/*
* ======== getXMLFromExec ========
* Retrieves the path to a given application's RTA XML file.
*/
public static String getXMLFromExec(String executable) throws Exception
{
return (MetaData.getXMLFromExec(executable));
}
/*
* ======== getTargetEventRecSize ========
* Returns the record size in bytes (not MAUs).
*/
public int getTargetEventRecSize()
{
return (this.meta == null ? 0 : this.meta.getTargetEventRecSize());
}
/*
* ======== parseFromExec ========
* Initializes the Decoder for the given executable.
*/
public String parseFromExec(String executable) throws Exception
{
MetaData nMeta = new MetaData();
String result = nMeta.parseFromExec(executable);
if (result == "") {
init(nMeta);
}
return (result);
}
/*
* ======== parse ========
* Initializes the Decoder for 'executable' given the path
* to the RTA XML file.
*/
public String parse(String xmlFile, String executable)
{
MetaData nMeta = new MetaData();
String result = nMeta.parse(xmlFile, executable);
if (result == "") {
init(nMeta);
}
return (result);
}
/*
* ======== apply ========
* Decodes the raw target bytes of a single event record into a HostEvent.
*/
public HostEvent apply(byte targetEventRec[])
{
return (apply(targetEventRec, 0));
}
/*
* ======== apply ========
* Decodes the raw target bytes of a single event record at the given
* offset. Returns a HostEvent object.
*/
public HostEvent apply(byte targetEventRec[], int offset)
{
/* Create a host event object to store the decoded event. */
HostEvent res = new HostEvent(meta);
/*
* Maintain a running offset into the buffer--update 'off' after
* reading each field of the record.
*
* The sizes of each field are the same across all targets, except
* for the arguments, which are of type IArg.
*
* struct EventRec {
* Bits32 ts_hi;
* Bits32 ts_lo;
* Bits32 serial;
* Bits32 evt;
* IArg arg[NUMARGS];
* }
*/
int off = offset;
/*
* Read the 64-bit time-stamp. It is stored as two 32-bit values which
* must be combined.
*/
/* Decode the upper 32-bits. */
long hi = decodeBytes(targetEventRec, off, 4, false);
off += 4;
/* Decode the lower 32-bits. */
long lo = decodeBytes(targetEventRec, off, 4, false);
off += 4;
/*
* Combine the upper and lower 32-bits to retrieve the 64-bit value.
*
* The 'timestamp' field is of type 'long', which is a signed 64-bit
* type, so it can only display a positive timestamp up to 2^63 - 1
* (If an unsigned long existed, it could display positive values up
* to 2^64 - 1).
*
* If the MSB of the timestamp is set (if bit 32 of 'hi' is set), then
* the timestamp value is too large, so just set the timestamp to -1.
* This likely indicates corrupt data (at 4GHz it would take
* over 73 years to reach 2^63), so -1 also serves as an indication
* that the data is corrupt.
*/
if (hi >= Math.pow(2, 31)) {
res.timestamp = -1L;
}
else {
/* Java cannot perform a 32-bit shift, so we must multiply. */
res.timestamp = (long) (hi * Math.pow(2, 32) + lo);
}
/* Read the 32-bit sequence number. */
res.sequenceNum = decodeBytes(targetEventRec, off, 4, false);
off += 4;
/* Read the 32-bit event code. */
long code = decodeBytes(targetEventRec, off, 4, false);
off += 4;
/*
* The event code contains the eventId in the upper 16-bits and the
* moduleId in the lower 16-bits.
*/
res.eventId = (int) code >> 16;
res.moduleId = (int) code & 0x0000FFFF;
/* Read all IArg arguments. */
/* The IArg size can vary between targets. */
int argSize = meta.getTargetArgSize();
for (int i = 0; i < 8; i++) {
res.args[i] = (int) decodeBytes(targetEventRec, off, argSize,
true);
off += argSize;
}
/* If this is a Log_print */
if (res.eventId == 0) {
/*
* The first argument in a Log_print record is the address of
* the format string.
* res.args[0] is a signed 32-bit value, but we need the address
* as an unsigned 32-bit value, so decode it again.
*/
res.formatAddr = decodeBytes(targetEventRec, offset + 16, argSize,
false);
}
return (res);
}
/*
* ======== decodeBytes ========
* This is a convenience method which exposes the TargetDecoder's
* 'decodeBytes' API.
*/
public long decodeBytes(byte buffer[], int offset, int size,
boolean signed)
{
return (this.targDecoder.decodeBytes(buffer, offset, size, signed));
}
/*
* ======== encodeArg ========
* This is a convenience method which exposes the TargetEncoder's
* 'encodeBytes' API.
*/
public void encodeArg(byte buf[], int offset, long arg, int size)
{
this.targEncoder.encodeBytes(buf, offset, arg, size);
}
/*
* ======== encode ========
* Encodes a HostEvent back into target bytes.
*/
public void encode(HostEvent evt, byte[] buf, int offset)
{
int off = offset;
int sz = 4;
/* Encode 64-bit time-stamp */
long hi = evt.timestamp / ((long) Math.pow(2, 32));
this.targEncoder.encodeBytes(buf, off, hi, sz);
off += sz;
long lo = evt.timestamp & 0x00000000FFFFFFFFl;
this.targEncoder.encodeBytes(buf, off, lo, sz);
off += sz;
/* Encode 32-bit sequence number */
this.targEncoder.encodeBytes(buf, off, evt.sequenceNum, sz);
off += sz;
/* Encode 32-bit event */
long code = (evt.eventId << 16) + evt.moduleId;
this.targEncoder.encodeBytes(buf, off, code, sz);
off += sz;
/* Encode all IArg arguments */
/* Size of the arguments in bytes */
sz = meta.getTargetArgSize();
for (int i = 0; i < evt.args.length; i++) {
this.targEncoder.encodeBytes(buf, off, evt.args[i], sz);
off += sz;
}
}
}