package com.oracle.truffle.llvm.parser.binary;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.llvm.parser.elf.ElfDynamicSection;
import com.oracle.truffle.llvm.parser.elf.ElfFile;
import com.oracle.truffle.llvm.parser.elf.ElfLibraryLocator;
import com.oracle.truffle.llvm.parser.elf.ElfSectionHeaderTable;
import com.oracle.truffle.llvm.parser.macho.MachOFile;
import com.oracle.truffle.llvm.parser.macho.MachOLibraryLocator;
import com.oracle.truffle.llvm.parser.macho.Xar;
import com.oracle.truffle.llvm.parser.scanner.BitStream;
import com.oracle.truffle.llvm.runtime.DefaultLibraryLocator;
import com.oracle.truffle.llvm.runtime.LLVMContext;
import com.oracle.truffle.llvm.runtime.LibraryLocator;
import com.oracle.truffle.llvm.runtime.Magic;
import org.graalvm.polyglot.io.ByteSequence;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public final class BinaryParser {
private ArrayList<String> libraries = new ArrayList<>();
private ArrayList<String> paths = new ArrayList<>();
private LibraryLocator locator = DefaultLibraryLocator.INSTANCE;
public static Magic getMagic(BitStream b) {
try {
return Magic.get(Integer.toUnsignedLong((int) b.read(0, Integer.SIZE)));
} catch (Exception e) {
return Magic.UNKNOWN;
}
}
public static BinaryParserResult parse(ByteSequence bytes, Source bcSource, LLVMContext context) {
return new BinaryParser().parseInternal(bytes, bcSource, context);
}
private BinaryParserResult parseInternal(ByteSequence bytes, Source bcSource, LLVMContext context) {
assert bytes != null;
ByteSequence bitcode = parseBitcode(bytes, bcSource);
if (bitcode == null) {
return null;
}
if (bcSource != null) {
LibraryLocator.traceParseBitcode(context, bcSource.getPath());
}
return new BinaryParserResult(libraries, paths, bitcode, locator, bcSource);
}
public static String getOrigin(Source source) {
if (source == null) {
return null;
}
String sourcePath = source.getPath();
if (sourcePath == null) {
return null;
}
Path parent = Paths.get(sourcePath).getParent();
if (parent == null) {
return null;
}
return parent.toString();
}
private ByteSequence parseBitcode(ByteSequence bytes, Source source) {
BitStream b = BitStream.create(bytes);
Magic magicWord = getMagic(b);
switch (magicWord) {
case BC_MAGIC_WORD:
return bytes;
case WRAPPER_MAGIC_WORD:
long offset = b.read(64, Integer.SIZE);
long size = b.read(96, Integer.SIZE);
return bytes.subSequence((int) offset, (int) (offset + size));
case ELF_MAGIC_WORD:
ElfFile elfFile = ElfFile.create(bytes);
ElfSectionHeaderTable.Entry llvmbc = elfFile.getSectionHeaderTable().getEntry(".llvmbc");
if (llvmbc == null) {
return null;
}
ElfDynamicSection dynamicSection = elfFile.getDynamicSection();
if (dynamicSection != null) {
List<String> elfLibraries = dynamicSection.getDTNeeded();
libraries.addAll(elfLibraries);
locator = new ElfLibraryLocator(elfFile, source);
}
long elfOffset = llvmbc.getOffset();
long elfSize = llvmbc.getSize();
return bytes.subSequence((int) elfOffset, (int) (elfOffset + elfSize));
case MH_MAGIC:
case MH_CIGAM:
case MH_MAGIC_64:
case MH_CIGAM_64:
MachOFile machOFile = MachOFile.create(bytes);
String origin = getOrigin(source);
List<String> machoLibraries = machOFile.getDyLibs(origin);
locator = new MachOLibraryLocator(machOFile, source);
libraries.addAll(machoLibraries);
ByteSequence machoBitcode = machOFile.extractBitcode();
if (machoBitcode == null) {
return null;
}
return parseBitcode(machoBitcode, source);
case XAR_MAGIC:
Xar xarFile = Xar.create(bytes);
ByteSequence xarBitcode = xarFile.extractBitcode();
if (xarBitcode == null) {
return null;
}
return parseBitcode(xarBitcode, source);
default:
return null;
}
}
}