/*
* Copyright 2016-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.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
// CHECKSTYLE.OFF: LocalVariableName
// CHECKSTYLE.OFF: ParameterName
public class ElfSymbolTable {
public final ImmutableList<Entry> entries;
public ElfSymbolTable(ImmutableList<Entry> entries) {
this.entries = entries;
}
public static ElfSymbolTable parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
ImmutableList.Builder<Entry> entries = ImmutableList.builder();
while (buffer.hasRemaining()) {
entries.add(Entry.parse(eiClass, buffer));
}
return new ElfSymbolTable(entries.build());
}
public void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
for (Entry entry : entries) {
entry.write(eiClass, buffer);
}
}
/** Encapsulate the data in an ELF section header. */
public static class Entry {
// CHECKSTYLE.OFF: MemberName
public final long st_name;
public final Info st_info;
public final int st_other;
public final int st_shndx;
public final long st_value;
public final long st_size;
// CHECKSTYLE.ON: MemberName
public Entry(
long st_name, Info st_info, int st_other, int st_shndx, long st_value, long st_size) {
this.st_name = st_name;
this.st_info = st_info;
this.st_other = st_other;
this.st_shndx = st_shndx;
this.st_value = st_value;
this.st_size = st_size;
}
/**
* @return either a 32- or 64-bit ELF symbol table entry header parsed from the given buffer.
*/
static Entry parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
long st_name = Elf.Elf32.getElf32Word(buffer);
long st_value = Elf.Elf32.getElf32Addr(buffer);
long st_size = Elf.Elf32.getElf32Word(buffer);
Info st_info = Info.parse(buffer);
int st_other = buffer.get();
int st_shndx = Elf.Elf32.getElf32Half(buffer);
return new Entry(st_name, st_info, st_other, st_shndx, st_value, st_size);
} else {
long st_name = Elf.Elf64.getElf64Word(buffer);
Info st_info = Info.parse(buffer);
int st_other = buffer.get();
int st_shndx = Elf.Elf64.getElf64Half(buffer);
long st_value = Elf.Elf64.getElf64Addr(buffer);
long st_size = Elf.Elf64.getElf64Xword(buffer);
return new Entry(st_name, st_info, st_other, st_shndx, st_value, st_size);
}
}
void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
Elf.Elf32.putElf32Word(buffer, (int) st_name);
Elf.Elf32.putElf32Addr(buffer, (int) st_value);
Elf.Elf32.putElf32Word(buffer, (int) st_size);
st_info.write(buffer);
buffer.put((byte) st_other);
Elf.Elf32.putElf32Half(buffer, (short) st_shndx);
} else {
Elf.Elf64.putElf64Word(buffer, (int) st_name);
st_info.write(buffer);
buffer.put((byte) st_other);
Elf.Elf64.putElf64Half(buffer, (short) st_shndx);
Elf.Elf64.putElf64Addr(buffer, st_value);
Elf.Elf64.putElf64Xword(buffer, st_size);
}
}
public static class Info {
// CHECKSTYLE.OFF: MemberName
public final Bind st_bind;
public final Type st_type;
// CHECKSTYLE.ON: MemberName
public Info(Bind st_bind, Type st_type) {
this.st_bind = st_bind;
this.st_type = st_type;
}
public static Info parse(ByteBuffer buffer) {
int st_info = buffer.get();
return new Info(Bind.ofIntValue(st_info >> 4), Type.ofIntValue(st_info & 0xF));
}
public void write(ByteBuffer buffer) {
buffer.put((byte) ((st_bind.value << 4) + (st_type.value & 0xF)));
}
public enum Bind {
STB_LOCAL(0),
STB_GLOBAL(1),
STB_WEAK(2),
;
private int value;
Bind(int value) {
this.value = value;
}
public static Bind ofIntValue(int val) {
for (Bind bind : values()) {
if (bind.value == val) {
return bind;
}
}
throw new IllegalArgumentException();
}
}
public enum Type {
STT_NOTYPE(0),
STT_OBJECT(1),
STT_FUNC(2),
STT_SECTION(3),
STT_FILE(4),
STT_COMMON(5),
STT_TLS(6),
;
private int value;
Type(int value) {
this.value = value;
}
public static Type ofIntValue(int val) {
for (Type type : values()) {
if (type.value == val) {
return type;
}
}
throw new IllegalArgumentException();
}
}
}
}
}