| /******************************************************************************* |
| * Copyright (c) 2004, 2008 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(); |
| } |
| } |