/******************************************************************************* * Copyright (c) 2004, 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 * oyvind.harboe@zylin.com - http://bugs.eclipse.org/250638 *******************************************************************************/ package org.eclipse.cdt.debug.internal.core.model; import java.math.BigInteger; import java.util.ArrayList; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.core.IAddressFactory; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.ICDebugConstants; import org.eclipse.cdt.debug.core.cdi.CDIException; import org.eclipse.cdt.debug.core.cdi.event.ICDIEvent; import org.eclipse.cdt.debug.core.cdi.event.ICDIEventListener; import org.eclipse.cdt.debug.core.cdi.event.ICDIMemoryChangedEvent; import org.eclipse.cdt.debug.core.cdi.model.ICDIInstruction; import org.eclipse.cdt.debug.core.cdi.model.ICDIMixedInstruction; import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; import org.eclipse.cdt.debug.core.model.ICStackFrame; import org.eclipse.cdt.debug.core.model.IDisassembly; import org.eclipse.cdt.debug.core.model.IDisassemblyBlock; import org.eclipse.cdt.debug.core.model.IExecFileInfo; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; /** * CDI implementation of IDisassembly */ public class Disassembly extends CDebugElement implements IDisassembly, ICDIEventListener { final static private int DISASSEMBLY_BLOCK_SIZE = 100; private DisassemblyBlock[] fBlocks = new DisassemblyBlock[1]; /** * Constructor for Disassembly. * * @param target */ public Disassembly( CDebugTarget target ) { super( target ); getCDISession().getEventManager().addEventListener( this ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.IDisassembly#getDisassemblyBlock(org.eclipse.cdt.debug.core.model.ICStackFrame) */ public IDisassemblyBlock getDisassemblyBlock( ICStackFrame frame ) throws DebugException { if ( fBlocks[0] == null || !fBlocks[0].contains( frame ) ) { fBlocks[0] = createBlock( frame ); } return fBlocks[0]; } private DisassemblyBlock createBlock( ICStackFrame frame ) throws DebugException { ICDITarget target = (ICDITarget)getDebugTarget().getAdapter( ICDITarget.class ); if ( target != null ) { String fileName = frame.getFile(); int lineNumber = frame.getLineNumber(); ICDIMixedInstruction[] mixedInstrs = new ICDIMixedInstruction[0]; IAddress address = frame.getAddress(); if (address==null) return null; if ( fileName != null && fileName.length() > 0 ) { try { mixedInstrs = target.getMixedInstructions( fileName, lineNumber, CDebugCorePlugin.getDefault().getPluginPreferences().getInt( ICDebugConstants.PREF_MAX_NUMBER_OF_INSTRUCTIONS ) ); } catch( CDIException e ) { // ignore and try to get disassembly without source } } // Double check if debugger returns correct address range. if ( mixedInstrs.length == 0 || !containsAddress( mixedInstrs, address ) ) { try { BigInteger addr = new BigInteger( address.toString() ); ICDIInstruction[] instructions = getFunctionInstructions( target.getInstructions( addr, addr.add( BigInteger.valueOf( DISASSEMBLY_BLOCK_SIZE ) ) ) ); return DisassemblyBlock.create( this, instructions ); } catch( CDIException e ) { targetRequestFailed( e.getMessage(), e ); } } else { return DisassemblyBlock.create( this, mixedInstrs ); } } return null; } public IDisassemblyBlock getDisassemblyBlock( IAddress address ) throws DebugException { fBlocks[0] = createBlock( address, null); return fBlocks[0]; } public IDisassemblyBlock getDisassemblyBlock( IAddress startAddress, IAddress endAddress ) throws DebugException { fBlocks[0] = createBlock( startAddress, endAddress ); return fBlocks[0]; } private DisassemblyBlock createBlock( IAddress startAddress, IAddress endAddress) throws DebugException { ICDITarget target = (ICDITarget)getDebugTarget().getAdapter( ICDITarget.class ); if ( target != null ) { ICDIMixedInstruction[] mixedInstrs = new ICDIMixedInstruction[0]; if ( mixedInstrs.length == 0 || !containsAddress( mixedInstrs, startAddress ) ) { try { BigInteger startAddr = new BigInteger( startAddress.toString() ); BigInteger endAddr = null; if (endAddress != null) { endAddr = new BigInteger( endAddress.toString() ); } else { endAddr = startAddr.add( BigInteger.valueOf( CDebugCorePlugin.getDefault().getPluginPreferences().getInt(ICDebugConstants.PREF_MAX_NUMBER_OF_INSTRUCTIONS))); } mixedInstrs = target.getMixedInstructions( startAddr, endAddr); return DisassemblyBlock.create( this, mixedInstrs ); } catch( CDIException e ) { targetRequestFailed( e.getMessage(), e ); } } else { return DisassemblyBlock.create( this, mixedInstrs ); } } return null; } private boolean containsAddress( ICDIMixedInstruction[] mi, IAddress address ) { for( int i = 0; i < mi.length; ++i ) { ICDIInstruction[] instructions = mi[i].getInstructions(); for ( int j = 0; j < instructions.length; ++j ) { if ( address.getValue().equals( instructions[j].getAdress() ) ) return true; } } return false; } private ICDIInstruction[] getFunctionInstructions( ICDIInstruction[] rawInstructions ) { if ( rawInstructions.length > 0 && rawInstructions[0].getFuntionName() != null && rawInstructions[0].getFuntionName().length() > 0 ) { ArrayList list = new ArrayList( rawInstructions.length ); list.add( rawInstructions[0] ); for( int i = 1; i < rawInstructions.length; ++i ) { if ( rawInstructions[0].getFuntionName().equals( rawInstructions[i].getFuntionName() ) ) { list.add( rawInstructions[i] ); } } return (ICDIInstruction[])list.toArray( new ICDIInstruction[list.size()] ); } return rawInstructions; } public void dispose() { getCDISession().getEventManager().removeEventListener( this ); CDebugCorePlugin.getDefault().getDisassemblyContextService().unregister( this ); for ( int i = 0; i < fBlocks.length; ++i ) if ( fBlocks[i] != null ) { fBlocks[i].dispose(); fBlocks[i] = null; } } /* (non-Javadoc) * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ @Override public Object getAdapter( Class adapter ) { if ( IExecFileInfo.class.equals( adapter ) ) return getDebugTarget().getAdapter( adapter ); return super.getAdapter( adapter ); } public void reset() { for ( int i = 0; i < fBlocks.length; ++i ) if ( fBlocks[i] != null ) { fBlocks[i].dispose(); fBlocks[i] = null; } fireChangeEvent( DebugEvent.CONTENT ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.IDisassembly#getAddressFactory() */ public IAddressFactory getAddressFactory() { return ((CDebugTarget)getDebugTarget()).getAddressFactory(); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.cdi.event.ICDIEventListener#handleDebugEvents(org.eclipse.cdt.debug.core.cdi.event.ICDIEvent[]) */ public void handleDebugEvents( ICDIEvent[] events ) { boolean update = false; for ( int i = 0; i < events.length; ++i ) { if ( events[i] instanceof ICDIMemoryChangedEvent ) { BigInteger[] addresses = ((ICDIMemoryChangedEvent)events[i]).getAddresses(); for ( int j = 0; j < addresses.length; ++j ) { IAddress address = getAddressFactory().createAddress( addresses[j] ); for ( int k = 0; k < fBlocks.length; ++k ) { if ( fBlocks[k] != null && fBlocks[k].contains( address ) ) { update = true; break; } } } } } if ( update ) reset(); } }