/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package flash.tools.debugger.concrete; import flash.swf.Action; import flash.swf.ActionConstants; import flash.swf.types.ActionList; import flash.swf.actions.DefineFunction; import flash.swf.debug.LineRecord; import flash.tools.ActionLocation; import flash.swf.MovieMetaData; import flash.tools.SwfActionContainer; import flash.util.Trace; /** * This class extends the SwfActionContainer. * It performs a number of passes on the master * action list in order to extract line/function * mapping information. */ public class LineFunctionContainer extends SwfActionContainer { public LineFunctionContainer(byte[] swf, byte[] swd) { super(swf, swd); // now that we've got all the action lists // nicely extracted and lined up we perform a // bit of magic which modifies the DefineFunction // records augmenting them with function names // if they have have none. buildFunctionNames(getMasterList(), getHeader().version); } /** * Use the action list located in the given location * and return a new action location that corresponds * to the next line record that is encountered * after this location. This routine does not * span into another action list. */ public ActionLocation endOfSourceLine(ActionLocation l) { ActionLocation current = new ActionLocation(l); int size = l.actions.size(); for(int i= l.at+1; i<size; i++) { // hit a line record => we done Action a = l.actions.getAction(i); if (a.code == ActionList.sactionLineRecord) break; // hit a function => we are done if ( (a.code == ActionConstants.sactionDefineFunction) || (a.code == ActionConstants.sactionDefineFunction2) ) break; current.at = i; } return current; } /** * This routine is called from the DSwfInfo object * and is used to obtain LineRecord information * from the ActionLists */ public void combForLineRecords(DSwfInfo info) { probeForLineRecords(getMasterList(), new ActionLocation(), info); } /** * This routine is called from the DSwfInfo object * and is used to obtain LineRecord information * from the ActionLists * * The ActionLocation record is used as a holding * container for state as we traverse the lists */ void probeForLineRecords(ActionList list, ActionLocation where, DSwfInfo info) { int size = list.size(); for(int i=0; i<size; i++) { try { // set our context where.at = i; where.actions = list; // pull the action Action a = list.getAction(i); // then see if we need to traverse if ( (a.code == ActionConstants.sactionDefineFunction) || (a.code == ActionConstants.sactionDefineFunction2) ) { where.function = (DefineFunction)a; probeForLineRecords(((DefineFunction)a).actionList, where, info); where.function = null; } else if (a.code == ActionList.sactionLineRecord) { // hit a line record, so let's do our callback info.processLineRecord(where, (LineRecord)a); } else if (a instanceof DummyAction) { // our dummy container, then we drop in where.className = ((DummyAction)a).getClassName(); probeForLineRecords(((DummyAction)a).getActionList(), where, info); where.className = null; } } catch(Exception e) { // this is fairly bad and probably means that we have corrupt line // records in the swd, the exception being an ArrayIndexOutOfBoundsException. // I've seen this in cases where a bad swc is built by authoring wherein a // script id collision occurs and thus the offset table will contain references // to line numbers that are non existent in one of the scripts. // If its another type of exception...well, hopefully the trace message will // help you track it down :) if (Trace.error) { Trace.trace("Error processing ActionList at "+where.at+" at offset "+where.actions.getOffset(where.at)+" in swf "+info.getUrl()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ e.printStackTrace(); } } } } /** * Go off and fill our DefineFunction records with function names. * @see MovieMetaData#walkActions for a discussion on how this is done. */ void buildFunctionNames(ActionList list, int version) { int size = list.size(); for(int i=0; i<size; i++) { DummyAction a = (DummyAction)list.getAction(i); MovieMetaData.walkActions( a.getActionList(), version, null, a.getClassName(), null ); } } }