/*
* Copyright 2014-present Facebook, Inc.
*
* Licensed 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 com.facebook.buck.cxx.elf;
import com.facebook.buck.model.Pair;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class Elf {
// The underlying buffer which contains the ELF file data.
private final ByteBuffer buffer;
public final ElfHeader header;
// A cache of parsed section headers.
private final List<ElfSection> sections;
public Elf(ByteBuffer buffer) {
this.buffer = Preconditions.checkNotNull(buffer);
// Eagerly parse the header, since we'll need this info for most/all operations.
this.header = ElfHeader.parse(this.buffer);
// Initialize a cache we'll use to store parsed section headers.
this.sections = new ArrayList<>(Collections.<ElfSection>nCopies(header.e_shnum, null));
}
public int getNumberOfSections() {
return header.e_shnum;
}
/** @return the parsed section header for the section at the given index. */
public ElfSection getSectionByIndex(int index) {
Preconditions.checkArgument(index >= 0 && index < header.e_shnum);
ElfSection section = sections.get(index);
if (section == null) {
buffer.position((int) (header.e_shoff + index * header.e_shentsize));
section = ElfSection.parse(header.ei_class, buffer);
sections.set(index, section);
}
return section;
}
/** @return the name of the section found in the section header string table. */
public String getSectionName(ElfSectionHeader sectionHeader) {
ElfSection stringTable = getSectionByIndex(header.e_shstrndx);
return stringTable.lookupString(sectionHeader.sh_name);
}
/** @return the parsed section header for the section of the given name. */
public Optional<Pair<Integer, ElfSection>> getSectionByName(String name) {
ElfSection stringTable = getSectionByIndex(header.e_shstrndx);
for (int index = 0; index < header.e_shnum; index++) {
ElfSection section = getSectionByIndex(index);
String sectionName = stringTable.lookupString(section.header.sh_name);
if (name.equals(sectionName)) {
return Optional.of(new Pair<>(index, section));
}
}
return Optional.empty();
}
public ElfSection getMandatorySectionByName(Object fileName, String sectionName)
throws IOException {
Optional<Pair<Integer, ElfSection>> result = getSectionByName(sectionName);
if (!result.isPresent()) {
throw new IOException(
String.format(
"Error parsing ELF file %s: no such section \"%s\"", fileName, sectionName));
}
return result.get().getSecond();
}
/** @return whether the data this buffer points to is most likely ELF. */
public static boolean isElf(ByteBuffer buffer) {
byte[] magic = new byte[4];
if (buffer.remaining() < magic.length) {
return false;
}
buffer.slice().get(magic);
return (magic[ElfHeader.EI_MAG0] == ElfHeader.ELFMAG0
&& magic[ElfHeader.EI_MAG1] == ElfHeader.ELFMAG1
&& magic[ElfHeader.EI_MAG2] == ElfHeader.ELFMAG2
&& magic[ElfHeader.EI_MAG3] == ElfHeader.ELFMAG3);
}
public static class Elf32 {
private Elf32() {}
public static long getElf32Addr(ByteBuffer buffer) {
return buffer.getInt() & 0xffffffffL;
}
public static void putElf32Addr(ByteBuffer buffer, int val) {
buffer.putInt(val);
}
public static long getElf32Word(ByteBuffer buffer) {
return buffer.getInt() & 0xffffffffL;
}
public static void putElf32Word(ByteBuffer buffer, int val) {
buffer.putInt(val);
}
public static int getElf32Half(ByteBuffer buffer) {
return buffer.getShort() & 0xffff;
}
public static void putElf32Half(ByteBuffer buffer, short val) {
buffer.putShort(val);
}
public static int getElf32Sword(ByteBuffer buffer) {
return buffer.getInt();
}
public static void putElf32Sword(ByteBuffer buffer, int val) {
buffer.putInt(val);
}
}
public static class Elf64 {
private Elf64() {}
public static long getElf64Addr(ByteBuffer buffer) {
return buffer.getLong();
}
public static void putElf64Addr(ByteBuffer buffer, long val) {
buffer.putLong(val);
}
public static long getElf64Word(ByteBuffer buffer) {
return (buffer.getInt() & 0xffffffffL);
}
public static void putElf64Word(ByteBuffer buffer, int val) {
buffer.putInt(val);
}
public static long getElf64Xword(ByteBuffer buffer) {
return buffer.getLong();
}
public static void putElf64Xword(ByteBuffer buffer, long val) {
buffer.putLong(val);
}
public static int getElf64Half(ByteBuffer buffer) {
return buffer.getShort() & 0xffff;
}
public static void putElf64Half(ByteBuffer buffer, short val) {
buffer.putShort(val);
}
public static long getElf64Sxword(ByteBuffer buffer) {
return buffer.getLong();
}
public static void putElf64Sxword(ByteBuffer buffer, long val) {
buffer.putLong(val);
}
}
}