diff -r 07b41fa8d1dd -r ca8a1b6995f6 tracefw/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/rules/osttrace/OstTraceParserRule.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tracefw/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/rules/osttrace/OstTraceParserRule.java Tue Aug 31 16:45:49 2010 +0300 @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + * All rights reserved. + * This component and the accompanying materials are made available + * under the terms of "Eclipse Public License v1.0" + * which accompanies this distribution, and is available + * at the URL "http://www.eclipse.org/legal/epl-v10.html". + * + * Initial Contributors: + * Nokia Corporation - initial contribution. + * + * Contributors: + * + * Description: + * + * OST trace parser rule + * + */ +package com.nokia.tracecompiler.engine.rules.osttrace; + +import java.util.ArrayList; +import java.util.List; + +import com.nokia.tracecompiler.engine.TraceLocation; +import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.TraceCompilerErrorCode; +import com.nokia.tracecompiler.engine.rules.AutoAddFunctionParametersRule; +import com.nokia.tracecompiler.engine.rules.AutoAddReturnParameterRule; +import com.nokia.tracecompiler.engine.rules.AutoAddThisPtrRule; +import com.nokia.tracecompiler.engine.rules.AutoAddValueRule; +import com.nokia.tracecompiler.engine.rules.AutomaticTraceTextRule; +import com.nokia.tracecompiler.engine.rules.ComplexHeaderRuleImpl; +import com.nokia.tracecompiler.engine.rules.EntryTraceRule; +import com.nokia.tracecompiler.engine.rules.ExitTraceRule; +import com.nokia.tracecompiler.engine.rules.PerformanceEventStartRule; +import com.nokia.tracecompiler.engine.rules.PerformanceEventStopRule; +import com.nokia.tracecompiler.engine.rules.ReadOnlyObjectRuleImpl; +import com.nokia.tracecompiler.engine.rules.SourceParserRuleBase; +import com.nokia.tracecompiler.engine.rules.StateTraceRule; +import com.nokia.tracecompiler.engine.source.SourceParserResult; +import com.nokia.tracecompiler.model.TraceCompilerException; +import com.nokia.tracecompiler.model.TraceModelExtension; +import com.nokia.tracecompiler.model.TraceParameter; +import com.nokia.tracecompiler.source.FormatMapping; +import com.nokia.tracecompiler.source.SourceContext; +import com.nokia.tracecompiler.source.SourceParser; + +/** + * OST trace parser rule + * + */ +public final class OstTraceParserRule extends SourceParserRuleBase { + + /** + * PERFORMANCE group name + */ + private static final String PERFORMANCE_GROUP_NAME = "TRACE_PERFORMANCE"; //$NON-NLS-1$ + + /** + * STATE group name + */ + private static final String STATE_GROUP_NAME = "TRACE_STATE"; //$NON-NLS-1$ + + /** + * FLOW group name + */ + private static final String FLOW_GROUP_NAME = "TRACE_FLOW"; //$NON-NLS-1$ + + /** + * Data trace parameter count + */ + private static final int DATA_PARAMETER_COUNT = 2; // CodForChk_Dis_Magic + + /** + * Entry Ext trace parameter count + */ + private static final int ENTRY_EXT_PARAMETER_COUNT = 1; // CodForChk_Dis_Magic + + /** + * Exit Ext trace parameter count + */ + private static final int EXIT_EXT_PARAMETER_COUNT = 2; // CodForChk_Dis_Magic + + /** + * Trace parameter index list + */ + class TraceParameterIndexList { + + /** + * Minimum number of parameters needed to decode traces + */ + int minParamCount; + + /** + * Preprocessor level index + */ + int levelIndex; + + /** + * Trace name index + */ + int nameIndex; + + /** + * Trace text index + */ + int textIndex; + + /** + * Trace group index in case group name is free-form + */ + int groupIndex; + + /** + * Trace group name in case group name is pre-determined by rules + */ + String groupName; + } + + /** + * List of flags related to OST API macro + */ + class TraceParameterFlagList { + + /** + * Data tag + */ + boolean hasDataTag; + + /** + * State tag + */ + boolean hasStateTag; + + /** + * Ext tag + */ + boolean hasExtTag; + + /** + * Event start tag + */ + boolean hasEventStartTag; + + /** + * Event stop + */ + boolean hasEventStopTag; + + /** + * Function entry + */ + boolean hasFunctionEntryTag; + + /** + * Function exit + */ + boolean hasFunctionExitTag; + + /** + * Constructor + * + * @param tag + * the trace tag + */ + TraceParameterFlagList(String tag) { + hasDataTag = tag.indexOf(OstConstants.DATA_TRACE_TAG) > 0; + hasStateTag = tag.indexOf(OstConstants.STATE_TRACE_TAG) > 0; + hasExtTag = tag.indexOf(OstConstants.EXTENSION_TRACE_TAG) > 0; + hasEventStartTag = tag + .indexOf(OstConstants.PERFORMANCE_EVENT_START_TAG) > 0; + hasEventStopTag = tag + .indexOf(OstConstants.PERFORMANCE_EVENT_STOP_TAG) > 0; + hasFunctionEntryTag = tag.indexOf(OstConstants.FUNCTION_ENTRY_TAG) > 0; + hasFunctionExitTag = tag.indexOf(OstConstants.FUNCTION_EXIT_TAG) > 0; + } + + /** + * Checks if any of the flags is set + * + * @return true if flag is set + */ + boolean hasFlags() { + return hasDataTag || hasStateTag || hasExtTag || hasEventStartTag + || hasEventStopTag || hasFunctionEntryTag + || hasFunctionExitTag; + } + + } + + /** + * Offset to preprocessor level + */ + private static final int PREPROCESSOR_LEVEL_OFFSET = 0; // CodForChk_Dis_Magic + + /** + * Offset to group name if preprocessor level is not in use + */ + private static final int GROUP_NAME_OFFSET = 0; // CodForChk_Dis_Magic + + /** + * Offset to trace name if preprocessor level is not in use + */ + private static final int TRACE_NAME_OFFSET = 1; // CodForChk_Dis_Magic + + /** + * Offset to trace text if preprocessor level is not in use + */ + private static final int TRACE_TEXT_OFFSET = 2; // CodForChk_Dis_Magic + + /** + * Minimum number of parameters if preprocessor level is not in use + */ + private static final int MIN_PARAMETER_COUNT = 3; // CodForChk_Dis_Magic + + /** + * Parser tag + */ + private static final String OST_TRACE_PARSER_TAG = "OstTrace"; //$NON-NLS-1$ + + /** + * OstTrace parser formats + */ + private final static String[] OST_TRACE_PARSER_FORMATS = { "0", //$NON-NLS-1$ + "1", //$NON-NLS-1$ + "Data", //$NON-NLS-1$ + "Ext?", //$NON-NLS-1$ + "FunctionEntry0", //$NON-NLS-1$ + "FunctionEntry1", //$NON-NLS-1$ + "FunctionEntryExt", //$NON-NLS-1$ + "FunctionExit0", //$NON-NLS-1$ + "FunctionExit1", //$NON-NLS-1$ + "FunctionExitExt", //$NON-NLS-1$ + "EventStart0", //$NON-NLS-1$ + "EventStart1", //$NON-NLS-1$ + "EventStop", //$NON-NLS-1$ + "Def0", //$NON-NLS-1$ + "Def1", //$NON-NLS-1$ + "DefData", //$NON-NLS-1$ + "DefExt?", //$NON-NLS-1$ + "State0", //$NON-NLS-1$ + "State1" //$NON-NLS-1$ + }; + + /** + * Creates a new OstTrace parser rule + */ + public OstTraceParserRule() { + super(OST_TRACE_PARSER_TAG, OST_TRACE_PARSER_FORMATS); + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracecompiler.engine.source.SourceParserRule#getName() + */ + @Override + public String getName() { + return OstTraceFormatRule.STORAGE_NAME; + } + + /* (non-Javadoc) + * @see com.nokia.tracecompiler.engine.rules.SourceParserRuleBase#parseParameters(java.lang.String, java.util.List) + */ + @Override + public SourceParserResult parseParameters(String tag, List list) + throws TraceCompilerException { + SourceParserResult result = new SourceParserResult(); + TraceParameterIndexList indexList = getIndexList(tag); + if (list.size() >= indexList.minParamCount) { + // Name must exist + result.originalName = list.get(indexList.nameIndex); + result.convertedName = result.originalName; + // Text is optional + if (indexList.textIndex >= 0) { + result.traceText = trimTraceText(list.get(indexList.textIndex)); + } else { + result.traceText = ""; //$NON-NLS-1$ + } + // Group ID and preprocessor level are stored into the + // parser-specific data + result.parserData = new ArrayList(); + if (indexList.levelIndex >= 0) { + result.parserData.add(list.get(indexList.levelIndex)); + } + if (indexList.groupIndex >= 0) { + result.parserData.add(list.get(indexList.groupIndex)); + } else if (indexList.groupName != null) { + result.parserData.add(indexList.groupName); + } + + // Extra parameters are converted to trace parameters + result.parameters = new ArrayList(); + for (int i = indexList.minParamCount; i < list.size(); i++) { + result.parameters.add(list.get(i)); + } + } else { + throw new TraceCompilerException( + TraceCompilerErrorCode.NOT_ENOUGH_PARAMETERS); + } + return result; + } + + /** + * Gets the parameter index list based on trace tag + * + * @param tag + * the trace tag + * @return the index list + */ + private TraceParameterIndexList getIndexList(String tag) { + TraceParameterIndexList indexes = new TraceParameterIndexList(); + indexes.levelIndex = -1; + if (tag.indexOf(OstConstants.FUNCTION_ENTRY_TAG) > 0 + || tag.indexOf(OstConstants.FUNCTION_EXIT_TAG) > 0) { + indexes.minParamCount = 1; // Name is mandatory + indexes.textIndex = -1; // No trace text + indexes.nameIndex = 0; // Trace name at index 0 + indexes.groupIndex = -1; // Group is fixed to TRACE_FLOW + indexes.groupName = FLOW_GROUP_NAME; + } else if (tag.indexOf(OstConstants.STATE_TRACE_TAG) > 0) { + indexes.minParamCount = 1; // Name is mandatory + indexes.textIndex = -1; // No trace text + indexes.nameIndex = 0; // Trace name at index 0 + indexes.groupIndex = -1; // Group is fixed to TRACE_STATE + indexes.groupName = STATE_GROUP_NAME; + } else if (tag.indexOf(OstConstants.PERFORMANCE_EVENT_START_TAG) > 0) { + // Name and event name are mandatory + indexes.minParamCount = 2; // CodForChk_Dis_Magic + indexes.textIndex = 1; // Trace text at index 1 + indexes.nameIndex = 0; // Trace name at index 0 + indexes.groupIndex = -1; // Group is fixed to TRACE_PERFORMANCE + indexes.groupName = PERFORMANCE_GROUP_NAME; + } else if (tag.indexOf(OstConstants.PERFORMANCE_EVENT_STOP_TAG) > 0) { + // Name and event name are mandatory + indexes.minParamCount = 2; // CodForChk_Dis_Magic + indexes.textIndex = 1; // Trace text at index 1 + indexes.nameIndex = 0; // Trace name at index 0 + indexes.groupIndex = -1; // Group is fixed to TRACE_PERFORMANCE + indexes.groupName = PERFORMANCE_GROUP_NAME; + } else { + indexes.minParamCount = MIN_PARAMETER_COUNT; + indexes.textIndex = TRACE_TEXT_OFFSET; + indexes.nameIndex = TRACE_NAME_OFFSET; + indexes.groupIndex = GROUP_NAME_OFFSET; + } + // If the trace macro contains preprocessor level, the offsets are + // incremented by one + if (tag.indexOf(OstConstants.PREPROCESSOR_LEVEL_TAG) > 0) { + indexes.minParamCount++; + if (indexes.textIndex >= 0) { + indexes.textIndex++; + } + if (indexes.nameIndex >= 0) { + indexes.nameIndex++; + } + if (indexes.groupIndex >= 0) { + indexes.groupIndex++; + } + indexes.levelIndex = PREPROCESSOR_LEVEL_OFFSET; + } + return indexes; + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracecompiler.engine.source.SourceParserRule# + * convertLocation(com.nokia.tracecompiler.engine.TraceLocation) + */ + @Override + public TraceConversionResult convertLocation(TraceLocation location) + throws TraceCompilerException { // CodForChk_Dis_ComplexFunc + TraceParameterFlagList flags = checkParameterCount(location); + + // Data tag does not have parameters + boolean checkParameters = !flags.hasDataTag; + + List typeList; + if (flags.hasExtTag + && (flags.hasFunctionEntryTag || flags.hasFunctionExitTag)) { + // Parameters are generated by AutoAdd rules + typeList = new ArrayList(); + checkParameters = false; + } else if (!flags.hasFlags() || flags.hasDataTag || flags.hasExtTag) { + // If the Ext, Data or EventStart tag is present, all formats + // are supported. If no flags is set, only 32-bit formats are + // supported. + typeList = buildParameterTypeList(location.getTraceText(), + !flags.hasDataTag && !flags.hasExtTag); + } else if (flags.hasEventStartTag) { + // In case of Start1 tag value parameter is supported + typeList = new ArrayList(); + // Check that does optional value exist + if (location.getParameterCount() == 1) { + FormatMapping mapping = new FormatMapping(TraceParameter.SDEC32); + mapping.isSimple = true; + typeList.add(mapping); + } + checkParameters = false; + } else if (flags.hasEventStopTag) { + // If the Event stop tag is presented, start event trace + // id parameter is supported + typeList = new ArrayList(); + FormatMapping mapping = new FormatMapping(TraceParameter.UDEC32); + mapping.isSimple = true; + typeList.add(mapping); + checkParameters = false; + + } else if (flags.hasStateTag) { + // If the State tag is presented, two ascii parameters are supported + // in case of State0 tag (parameter count = 2). In case of State1 + // tag (parameter count = 3) two ascii and one 32-bit hex parameters + // are supported + typeList = new ArrayList(); + FormatMapping mapping = new FormatMapping(TraceParameter.ASCII); + mapping.isSimple = true; + typeList.add(mapping); + mapping = new FormatMapping(TraceParameter.ASCII); + mapping.isSimple = true; + typeList.add(mapping); + + // Check that does optional instance identifier exist + if (location.getParameterCount() == 3) { // CodForChk_Dis_Magic + mapping = new FormatMapping(TraceParameter.HEX32); + mapping.isSimple = true; + typeList.add(mapping); + } + checkParameters = false; + } else { + // If some other flag than Data, State, Ext or EventStart is set, + // only one 32-bit hex parameter is supported + typeList = new ArrayList(); + if (location.getParameterCount() == 1) { + FormatMapping mapping = new FormatMapping(TraceParameter.HEX32); + mapping.isSimple = true; + typeList.add(mapping); + } + } + // If no flags or Ext flag is present, the parameter count needs to be + // verified + TraceConversionResult result = super.convertLocation(location, + checkParameters, typeList); + // If the extension or state tag is present, zero parameters or a single + // 32-bit parameter is not accepted because they do not need to generate + // a function into the header + if (((flags.hasExtTag && !flags.hasFunctionExitTag && !flags.hasFunctionEntryTag) || (flags.hasStateTag)) + && (typeList.size() == 0 || (typeList.size() == 1 && typeList + .get(0).isSimple))) { + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_FORMAT_UNNECESSARY_EXT_MACRO); + } + // Ext-macros are tagged with the complex header rule, so the header + // gets written when traces are exported. Data-macros are tagged with + // read-only rule, so they are not updated via UI. Other special cases + // are flagged with corresponding rule. + // If trace text does not exist, it is created based on context + AutomaticTraceTextRule rule = null; + if (flags.hasDataTag) { + addRule(result, new ReadOnlyObjectRuleImpl()); + } else if (flags.hasStateTag) { + addRule(result, new StateTraceRule()); + addRule(result, new ComplexHeaderRuleImpl()); + } else if (flags.hasEventStartTag) { + addRule(result, new PerformanceEventStartRule()); + // If event value is not defined then event value 1 is automatically + // added to event start macros + if (location.getParameterCount() == 0) { + addRule(result, new AutoAddValueRule()); + } + } else if (flags.hasEventStopTag) { + addRule(result, new PerformanceEventStopRule()); + addRule(result, new ComplexHeaderRuleImpl()); + // Event value 0 is automatically added to event stop macros + addRule(result, new AutoAddValueRule()); + } else if (flags.hasFunctionEntryTag) { + if (flags.hasExtTag) { + // Entry trace may contain Ext tag. In that case the trace + // parameters are an instance variable and function parameters + // parsed from source. It is also flagged as complex, so the + // function gets generated to the trace header + addRule(result, new ComplexHeaderRuleImpl()); + addRule(result, new AutoAddFunctionParametersRule()); + addRule(result, new AutoAddThisPtrRule()); + } + rule = new EntryTraceRule(); + addRule(result, rule); + } else if (flags.hasFunctionExitTag) { + if (flags.hasExtTag) { + // Exit trace may contain Ext tag. In that case the trace has + // two parameters: instance variable and return statement + // It is also flagged as complex, so the function gets generated + // to the trace header + addRule(result, new ComplexHeaderRuleImpl()); + addRule(result, new AutoAddThisPtrRule()); + addRule(result, new AutoAddReturnParameterRule()); + } + rule = new ExitTraceRule(); + addRule(result, rule); + } else if (flags.hasExtTag) { + addRule(result, new ComplexHeaderRuleImpl()); + } + if (rule != null) { + setAutoTextToTrace(location, result, rule); + } + List parserData = location.getParserData(); + result.group = parserData.get(parserData.size() - 1); + // The convert flag is reset to prevent further conversions + location.locationConverted(); + return result; + } + + /** + * Uses the auto-text rule to create trace text + * + * @param location + * the location + * @param result + * the conversion result + * @param rule + * the auto-text rule + * @throws TraceCompilerException + * if update fails + */ + private void setAutoTextToTrace(TraceLocation location, + TraceConversionResult result, AutomaticTraceTextRule rule) + throws TraceCompilerException { + // The trace text comes from the auto-text rule + SourceParser parser = location.getParser(); + SourceContext context = parser.getContext(location.getOffset()); + if (context != null) { + result.text = rule.formatTrace(context); + } else { + throw new TraceCompilerException( + TraceCompilerErrorCode.NO_CONTEXT_FOR_LOCATION); + } + } + + /** + * Checks parameter count + * + * @param location + * the location + * @return the location tag flags + * @throws TraceCompilerException + * if parameter count is not valid + */ + private TraceParameterFlagList checkParameterCount(TraceLocation location) + throws TraceCompilerException { + TraceParameterFlagList flags = new TraceParameterFlagList(location + .getTag()); + + // If the trace has some tag, the parameter count is fixed + // Data has 2 parameters + // State has 2 or 3 parameters + // Function entry-exit has 0 or 1 parameters + // Event start has 0 or 1 parameters + // Event stop has 1 parameters + int parameterCount = location.getParameterCount(); + + // Entry trace may have zero or one parameter + // In case of Ext, it must have one parameter + if (flags.hasFunctionEntryTag + && ((parameterCount > 1) || (flags.hasExtTag && (parameterCount != ENTRY_EXT_PARAMETER_COUNT)))) { + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + // Exit trace may have zero or one parameter + // In case of Ext, it must have two parameters + if (flags.hasFunctionExitTag + && ((!flags.hasExtTag && (parameterCount > 1)) || (flags.hasExtTag && parameterCount != EXIT_EXT_PARAMETER_COUNT))) { // CodForChk_Dis_LengthyLine + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + // Event start may have zero or one parameter + if (flags.hasEventStartTag && (parameterCount > 1)) { + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + // Event stop have one parameters + if (flags.hasEventStopTag && (parameterCount != 1)) { + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + // Data trace has two parameters + if ((flags.hasDataTag && (parameterCount != DATA_PARAMETER_COUNT))) { + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + // State trace may have two or three parameter + if (flags.hasStateTag && (parameterCount < 2 || parameterCount > 3)) { // CodForChk_Dis_Magic + throw new TraceCompilerException( + TraceCompilerErrorCode.PARAMETER_COUNT_DOES_NOT_MATCH_API); + } + + return flags; + } + + /** + * Adds a rule to result + * + * @param result + * the result + * @param rule + * the rule + */ + private void addRule(TraceConversionResult result, TraceModelExtension rule) { + if (result.extensions == null) { + result.extensions = new ArrayList(); + } + result.extensions.add(rule); + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracecompiler.engine.rules.SourceParserRuleBase# + * isLocationConverted(com.nokia.tracecompiler.engine.TraceLocation) + */ + @Override + public boolean isLocationConverted(TraceLocation location) { + boolean retval = location.hasChangedAfterConvert(); + if (!retval) { + // Duplicate-location conversions need to be retried in case the + // location is no longer a duplicate + retval = (location.getValidityCode() == TraceCompilerErrorCode.TRACE_HAS_MULTIPLE_LOCATIONS); + } + return retval; + } + + /* + * (non-Javadoc) + * + * @seecom.nokia.tracecompiler.engine.rules.printf.PrintfTraceParserRule# + * getLocationGroup() + */ + @Override + public String getLocationGroup() { + return null; + } +}