/*
* 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.facebook.buck.model.Pair;
import com.facebook.buck.util.MoreIterables;
import com.facebook.buck.util.RichStream;
import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
public class ElfVerDef {
public final ImmutableList<Pair<Verdef, ImmutableList<Verdaux>>> entries;
public ElfVerDef(ImmutableList<Pair<Verdef, ImmutableList<Verdaux>>> entries) {
this.entries = entries;
}
public static ElfVerDef parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
ImmutableList.Builder<Pair<Verdef, ImmutableList<Verdaux>>> entries = ImmutableList.builder();
int vdPos = buffer.position();
while (buffer.hasRemaining()) {
buffer.position(vdPos);
Verdef verdef = Verdef.parse(eiClass, buffer);
int vdaPos = vdPos + (int) verdef.vd_aux;
ImmutableList.Builder<Verdaux> verdauxEntries = ImmutableList.builder();
for (int j = 0; j < verdef.vd_cnt; j++) {
buffer.position(vdaPos);
Verdaux verdaux = Verdaux.parse(eiClass, buffer);
verdauxEntries.add(verdaux);
vdaPos += (int) verdaux.vda_next;
}
entries.add(new Pair<>(verdef, verdauxEntries.build()));
if (verdef.vd_next == 0) {
break;
}
vdPos += verdef.vd_next;
}
return new ElfVerDef(entries.build());
}
public void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
int vdPos = buffer.position();
for (Pair<Verdef, ImmutableList<Verdaux>> entry : entries) {
Verdef verdef = entry.getFirst();
ImmutableList<Verdaux> verdauxEntries = entry.getSecond();
buffer.position(vdPos);
verdef.write(eiClass, buffer);
int vdaPos = vdPos + (int) verdef.vd_aux;
for (Verdaux verdaux : verdauxEntries) {
buffer.position(vdaPos);
verdaux.write(eiClass, buffer);
vdaPos += verdaux.vda_next;
}
vdPos += verdef.vd_next;
}
}
public ElfVerDef compact() {
return new ElfVerDef(
RichStream.from(MoreIterables.enumerate(this.entries))
.map(
vdp -> {
int verdefIndex = vdp.getFirst();
Verdef verdef = vdp.getSecond().getFirst();
ImmutableList<Verdaux> verdauxes = vdp.getSecond().getSecond();
return new Pair<>(
new Verdef(
verdef.vd_version,
verdef.vd_flags,
verdef.vd_ndx,
verdauxes.size(),
verdef.vd_hash,
verdauxes.size() == 0 ? 0 : Verdef.BYTES,
verdefIndex == entries.size() - 1
? 0
: Verdef.BYTES + Verdaux.BYTES * verdauxes.size()),
RichStream.from(MoreIterables.enumerate(verdauxes))
.map(
vdxp ->
new Verdaux(
vdxp.getSecond().vda_name,
vdxp.getFirst() == verdauxes.size() - 1 ? 0 : Verdaux.BYTES))
.toImmutableList());
})
.toImmutableList());
}
public static class Verdef {
private static final int BYTES = 20;
// CHECKSTYLE.OFF: MemberName
public final int vd_version;
public final int vd_flags;
public final int vd_ndx;
public final int vd_cnt;
public final long vd_hash;
public final long vd_aux;
public final long vd_next;
// CHECKSTYLE.ON: MemberName
// CHECKSTYLE.OFF: ParameterName
public Verdef(
int vd_version,
int vd_flags,
int vd_ndx,
int vd_cnt,
long vd_hash,
long vd_aux,
long vd_next) {
this.vd_version = vd_version;
this.vd_flags = vd_flags;
this.vd_ndx = vd_ndx;
this.vd_cnt = vd_cnt;
this.vd_hash = vd_hash;
this.vd_aux = vd_aux;
this.vd_next = vd_next;
}
// CHECKSTYLE.ON: ParameterName
private static Verdef parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
return new Verdef(
Elf.Elf32.getElf32Half(buffer),
Elf.Elf32.getElf32Half(buffer),
Elf.Elf32.getElf32Half(buffer),
Elf.Elf32.getElf32Half(buffer),
Elf.Elf32.getElf32Word(buffer),
Elf.Elf32.getElf32Word(buffer),
Elf.Elf32.getElf32Word(buffer));
} else {
return new Verdef(
Elf.Elf64.getElf64Half(buffer),
Elf.Elf64.getElf64Half(buffer),
Elf.Elf64.getElf64Half(buffer),
Elf.Elf64.getElf64Half(buffer),
Elf.Elf64.getElf64Word(buffer),
Elf.Elf64.getElf64Word(buffer),
Elf.Elf64.getElf64Word(buffer));
}
}
private void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
Elf.Elf32.putElf32Half(buffer, (short) vd_version);
Elf.Elf32.putElf32Half(buffer, (short) vd_flags);
Elf.Elf32.putElf32Half(buffer, (short) vd_ndx);
Elf.Elf32.putElf32Half(buffer, (short) vd_cnt);
Elf.Elf32.putElf32Word(buffer, (int) vd_hash);
Elf.Elf32.putElf32Word(buffer, (int) vd_aux);
Elf.Elf32.putElf32Word(buffer, (int) vd_next);
} else {
Elf.Elf64.putElf64Half(buffer, (short) vd_version);
Elf.Elf64.putElf64Half(buffer, (short) vd_flags);
Elf.Elf64.putElf64Half(buffer, (short) vd_ndx);
Elf.Elf64.putElf64Half(buffer, (short) vd_cnt);
Elf.Elf64.putElf64Word(buffer, (int) vd_hash);
Elf.Elf64.putElf64Word(buffer, (int) vd_aux);
Elf.Elf64.putElf64Word(buffer, (int) vd_next);
}
}
}
public static class Verdaux {
private static final int BYTES = 8;
// CHECKSTYLE.OFF: MemberName
public final long vda_name;
public final long vda_next;
// CHECKSTYLE.ON: MemberName
// CHECKSTYLE.OFF: ParameterName
public Verdaux(long vda_name, long vda_next) {
this.vda_name = vda_name;
this.vda_next = vda_next;
}
// CHECKSTYLE.ON: ParameterName
private static Verdaux parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
return new Verdaux(Elf.Elf32.getElf32Word(buffer), Elf.Elf32.getElf32Word(buffer));
} else {
return new Verdaux(Elf.Elf64.getElf64Word(buffer), Elf.Elf64.getElf64Word(buffer));
}
}
private void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) {
if (eiClass == ElfHeader.EIClass.ELFCLASS32) {
Elf.Elf32.putElf32Word(buffer, (int) vda_name);
Elf.Elf32.putElf32Word(buffer, (int) vda_next);
} else {
Elf.Elf64.putElf64Word(buffer, (int) vda_name);
Elf.Elf64.putElf64Word(buffer, (int) vda_next);
}
}
}
}