blob: 5a141545dc1843b98890b73466188e9ee81b135d [file] [log] [blame]
/*
* 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 java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Encapsulate the data found in an ELF header.
*/
public class ElfHeader {
public static final int EI_MAG0 = 0;
public static final int EI_MAG1 = 1;
public static final int EI_MAG2 = 2;
public static final int EI_MAG3 = 3;
public static final int EI_CLASS = 4;
public static final int EI_DATA = 5;
public static final int EI_VERSION = 6;
public static final int EI_PAD = 7;
public static final int EI_NIDENT = 16;
public static final byte ELFMAG0 = 0x7f;
public static final byte ELFMAG1 = 'E';
public static final byte ELFMAG2 = 'L';
public static final byte ELFMAG3 = 'F';
public final EIClass ei_class;
public final EIData ei_data;
public final short e_type;
public final short e_machine;
public final int e_version;
public final long e_entry;
public final long e_phoff;
public final long e_shoff;
public final int e_flags;
public final short e_ehsize;
public final short e_phentsize;
public final short e_phnum;
public final short e_shentsize;
public final short e_shnum;
public final short e_shstrndx;
ElfHeader(
EIClass ei_class,
EIData ei_data,
short e_type,
short e_machine,
int e_version,
long e_entry,
long e_phoff,
long e_shoff,
int e_flags,
short e_ehsize,
short e_phentsize,
short e_phnum,
short e_shentsize,
short e_shnum,
short e_shstrndx) {
this.ei_class = ei_class;
this.ei_data = ei_data;
this.e_type = e_type;
this.e_machine = e_machine;
this.e_version = e_version;
this.e_entry = e_entry;
this.e_phoff = e_phoff;
this.e_shoff = e_shoff;
this.e_flags = e_flags;
this.e_ehsize = e_ehsize;
this.e_phentsize = e_phentsize;
this.e_phnum = e_phnum;
this.e_shentsize = e_shentsize;
this.e_shnum = e_shnum;
this.e_shstrndx = e_shstrndx;
}
/**
* @return a {@link ElfHeader} parsed from the given buffer.
*/
static ElfHeader parse(ByteBuffer buffer) {
byte[] e_ident = new byte[EI_NIDENT];
buffer.get(e_ident);
// Read the data field to determine endian-ness. We use this to set the byte order
// for the underlying buffer.
EIData ei_data = EIData.valueOf(e_ident[EI_DATA]);
ei_data.setOrder(buffer);
// Read the class field to determine whether we're parsing for 32-bit or 64-bit.
EIClass ei_class = EIClass.valueOf(e_ident[EI_CLASS]);
return ei_class.parseHeader(ei_data, buffer);
}
public static enum EIClass {
ELFCLASSNONE(0) {
@Override
ElfHeader parseHeader(EIData ei_data, ByteBuffer buffer) {
throw new IllegalStateException();
}
},
ELFCLASS32(1) {
@Override
ElfHeader parseHeader(EIData ei_data, ByteBuffer buffer) {
return new ElfHeader(
this,
ei_data,
buffer.getShort(),
buffer.getShort(),
buffer.getInt(),
buffer.getInt(),
buffer.getInt(),
buffer.getInt(),
buffer.getInt(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort());
}
},
ELFCLASS64(2) {
@Override
ElfHeader parseHeader(EIData ei_data, ByteBuffer buffer) {
return new ElfHeader(
this,
ei_data,
buffer.getShort(),
buffer.getShort(),
buffer.getInt(),
buffer.getLong(),
buffer.getLong(),
buffer.getLong(),
buffer.getInt(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort(),
buffer.getShort());
}
}
;
private final int value;
private EIClass(int value) {
this.value = value;
}
static EIClass valueOf(int val) {
for (EIClass clazz : EIClass.values()) {
if (clazz.value == val) {
return clazz;
}
}
throw new IllegalStateException();
}
abstract ElfHeader parseHeader(EIData ei_data, ByteBuffer buffer);
}
public static enum EIData {
ELFDATANONE(0) {
@Override
void setOrder(ByteBuffer buffer) {
throw new IllegalStateException();
}
},
ELFDATA2LSB(1) {
@Override
void setOrder(ByteBuffer buffer) {
buffer.order(ByteOrder.LITTLE_ENDIAN);
}
},
ELFDATA2MSB(2) {
@Override
void setOrder(ByteBuffer buffer) {
buffer.order(ByteOrder.BIG_ENDIAN);
}
},
;
private final int value;
private EIData(int value) {
this.value = value;
}
abstract void setOrder(ByteBuffer buffer);
static EIData valueOf(int val) {
for (EIData data : EIData.values()) {
if (data.value == val) {
return data;
}
}
throw new IllegalStateException();
}
}
}