| /* --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; |
| } |
| } |
| } |