| /******************************************************************************* |
| * Copyright (c) 2000, 2012 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 |
| * Anton Leherbauer (Wind River Systems) |
| * Hansruedi Patzen (IFS) |
| *******************************************************************************/ |
| package org.eclipse.cdt.utils.elf.parser; |
| |
| import static org.eclipse.cdt.internal.core.ByteUtils.makeShort; |
| import static org.eclipse.cdt.internal.core.ByteUtils.makeInt; |
| |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.util.Arrays; |
| |
| import org.eclipse.cdt.core.AbstractCExtension; |
| import org.eclipse.cdt.core.CCorePlugin; |
| import org.eclipse.cdt.core.IBinaryParser; |
| import org.eclipse.cdt.utils.AR; |
| import org.eclipse.cdt.utils.elf.Elf; |
| import org.eclipse.cdt.utils.elf.Elf.Attribute; |
| import org.eclipse.cdt.utils.elf.Elf.ELFhdr; |
| import org.eclipse.cdt.utils.elf.Elf.PHdr; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| |
| /** |
| */ |
| public class ElfParser extends AbstractCExtension implements IBinaryParser { |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.IBinaryParser#getBinary(org.eclipse.core.runtime.IPath) |
| */ |
| @Override |
| public IBinaryFile getBinary(IPath path) throws IOException { |
| return getBinary(null, path); |
| } |
| |
| |
| @Override |
| public IBinaryFile getBinary(byte[] hints, IPath path) throws IOException { |
| if (path == null) { |
| throw new IOException(CCorePlugin.getResourceString("Util.exception.nullPath")); //$NON-NLS-1$ |
| } |
| |
| IBinaryFile binary = null; |
| if (hints != null && AR.isARHeader(hints)) { |
| binary = createBinaryArchive(path); |
| } else { |
| try { |
| Attribute attribute = getAttribute(hints, path); |
| |
| if (attribute != null) { |
| switch (attribute.getType()) { |
| case Attribute.ELF_TYPE_EXE : |
| binary = createBinaryExecutable(path); |
| break; |
| |
| case Attribute.ELF_TYPE_SHLIB : |
| binary = hasInterpProgramHeader(hints, path) ? createBinaryExecutable(path) : createBinaryShared(path); |
| break; |
| |
| case Attribute.ELF_TYPE_OBJ : |
| binary = createBinaryObject(path); |
| break; |
| |
| case Attribute.ELF_TYPE_CORE : |
| binary = createBinaryCore(path); |
| break; |
| } |
| if (binary instanceof ElfBinaryObject) { |
| ((ElfBinaryObject)binary).setElfAttributes(attribute); |
| } |
| } |
| } catch (IOException e) { |
| if (hints == null) { |
| try { |
| binary = createBinaryArchive(path); |
| } catch (IOException e2) { |
| CCorePlugin.log(e); // log original exception |
| throw e2; |
| } |
| } |
| } |
| } |
| return binary; |
| } |
| |
| /** |
| * @see org.eclipse.cdt.core.IBinaryParser#getFormat() |
| */ |
| @Override |
| public String getFormat() { |
| return "ELF"; //$NON-NLS-1$ |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.IBinaryParser#isBinary(byte[], org.eclipse.core.runtime.IPath) |
| */ |
| @Override |
| public boolean isBinary(byte[] array, IPath path) { |
| return Elf.isElfHeader(array) || AR.isARHeader(array); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.IBinaryParser#getBufferSize() |
| */ |
| @Override |
| public int getHintBufferSize() { |
| return 128; |
| } |
| |
| protected IBinaryArchive createBinaryArchive(IPath path) throws IOException { |
| return new ElfBinaryArchive(this, path); |
| } |
| |
| protected IBinaryObject createBinaryObject(IPath path) throws IOException { |
| return new ElfBinaryObject(this, path, IBinaryFile.OBJECT); |
| } |
| |
| protected IBinaryExecutable createBinaryExecutable(IPath path) throws IOException { |
| return new ElfBinaryExecutable(this, path); |
| } |
| |
| protected IBinaryShared createBinaryShared(IPath path) throws IOException { |
| return new ElfBinaryShared(this, path); |
| } |
| |
| protected IBinaryObject createBinaryCore(IPath path) throws IOException { |
| return new ElfBinaryObject(this, path, IBinaryFile.CORE); |
| } |
| |
| private static Elf.Attribute getAttribute(byte[] hints, IPath path) throws IOException { |
| if (Elf.isElfHeader(hints)) { |
| try { |
| return Elf.getAttributes(hints); |
| } catch (EOFException eof) { |
| // continue, the array was to small. |
| } |
| } |
| return Elf.getAttributes(path.toOSString()); |
| } |
| |
| private static boolean hasInterpProgramHeader(byte[] hints, IPath path) throws IOException { |
| if (Elf.isElfHeader(hints)) { |
| int e_phentsizeOffset = 0; |
| int e_phnumOffset = 0; |
| int e_ehsizeOffset = 0; |
| switch (hints[ELFhdr.EI_CLASS]) { |
| case ELFhdr.ELFCLASS32: |
| e_ehsizeOffset = 0x28; |
| e_phentsizeOffset = 0x2A; |
| e_phnumOffset = 0x2C; |
| break; |
| case ELFhdr.ELFCLASS64: |
| e_ehsizeOffset = 0x34; |
| e_phentsizeOffset = 0x36; |
| e_phnumOffset = 0x38; |
| break; |
| default: |
| CCorePlugin.log(IStatus.WARNING, "Unknown ELF header class in file: " + path.toOSString()); //$NON-NLS-1$ |
| return false; |
| } |
| if (e_phnumOffset + 2 < hints.length) { |
| boolean isle = (hints[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB); |
| short e_phentsize = makeShort(hints, e_phentsizeOffset, isle); |
| short e_phnum = makeShort(hints, e_phnumOffset, isle); |
| short e_ehsize = makeShort(hints, e_ehsizeOffset, isle); |
| int lastProgramHeaderOffset = e_ehsize + (e_phnum - 1) * e_phentsize; |
| for (int i = e_ehsize; i < Math.min(lastProgramHeaderOffset, hints.length) + 4; i += e_phentsize) { |
| if (makeInt(hints, i, isle) == PHdr.PT_INTERP) { |
| return true; |
| } |
| } |
| /* See if we checked every program header type */ |
| if (lastProgramHeaderOffset + 4 < hints.length) { |
| return false; |
| } |
| } |
| } |
| |
| try { |
| /* No PHdr.PT_INTERP found in the hints meaning we need to read the file itself */ |
| return Arrays.stream(new Elf(path.toOSString()).getPHdrs()).anyMatch(phdr -> phdr.p_type == PHdr.PT_INTERP); |
| } catch (IOException e) { |
| CCorePlugin.log(e); |
| } |
| return false; |
| } |
| } |