/* * 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 ElfVerNeed { public final ImmutableList<Pair<Verneed, ImmutableList<Vernaux>>> entries; public ElfVerNeed(ImmutableList<Pair<Verneed, ImmutableList<Vernaux>>> entries) { this.entries = entries; } public static ElfVerNeed parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) { ImmutableList.Builder<Pair<Verneed, ImmutableList<Vernaux>>> entries = ImmutableList.builder(); int vnPos = buffer.position(); while (true) { buffer.position(vnPos); Verneed verneed = Verneed.parse(eiClass, buffer); int vnaPos = vnPos + (int) verneed.vn_aux; ImmutableList.Builder<Vernaux> vernauxEntries = ImmutableList.builder(); for (int j = 0; j < verneed.vn_cnt; j++) { buffer.position(vnaPos); Vernaux vernaux = Vernaux.parse(eiClass, buffer); vernauxEntries.add(vernaux); vnaPos += (int) vernaux.vna_next; } entries.add(new Pair<>(verneed, vernauxEntries.build())); if (verneed.vn_next == 0) { break; } vnPos += verneed.vn_next; } return new ElfVerNeed(entries.build()); } public void write(ElfHeader.EIClass eiClass, ByteBuffer buffer) { int vnPos = buffer.position(); for (Pair<Verneed, ImmutableList<Vernaux>> entry : entries) { Verneed verneed = entry.getFirst(); ImmutableList<Vernaux> vernauxEntries = entry.getSecond(); buffer.position(vnPos); verneed.write(eiClass, buffer); int vnaPos = vnPos + (int) verneed.vn_aux; for (Vernaux vernaux : vernauxEntries) { buffer.position(vnaPos); vernaux.write(eiClass, buffer); vnaPos += vernaux.vna_next; } vnPos += verneed.vn_next; } } public ElfVerNeed compact() { return new ElfVerNeed( RichStream.from(MoreIterables.enumerate(this.entries)) .map( vnp -> { int verneedIndex = vnp.getFirst(); ElfVerNeed.Verneed verneed = vnp.getSecond().getFirst(); ImmutableList<ElfVerNeed.Vernaux> vernauxes = vnp.getSecond().getSecond(); return new Pair<>( new ElfVerNeed.Verneed( verneed.vn_version, vernauxes.size(), verneed.vn_file, vernauxes.size() == 0 ? 0 : ElfVerNeed.Verneed.BYTES, verneedIndex == entries.size() - 1 ? 0 : ElfVerNeed.Verneed.BYTES + ElfVerNeed.Vernaux.BYTES * vernauxes.size()), RichStream.from(MoreIterables.enumerate(vernauxes)) .map( vnxp -> new ElfVerNeed.Vernaux( vnxp.getSecond().vna_hash, vnxp.getSecond().vna_flags, vnxp.getSecond().vna_other, vnxp.getSecond().vna_name, vnxp.getFirst() == vernauxes.size() - 1 ? 0 : ElfVerNeed.Vernaux.BYTES)) .toImmutableList()); }) .toImmutableList()); } public static class Verneed { private static final int BYTES = 16; // CHECKSTYLE.OFF: MemberName public final int vn_version; public final int vn_cnt; public final long vn_file; public final long vn_aux; public final long vn_next; // CHECKSTYLE.ON: MemberName // CHECKSTYLE.OFF: ParameterName public Verneed(int vn_version, int vn_cnt, long vn_file, long vn_aux, long vn_next) { this.vn_version = vn_version; this.vn_cnt = vn_cnt; this.vn_file = vn_file; this.vn_aux = vn_aux; this.vn_next = vn_next; } // CHECKSTYLE.ON: ParameterName private static Verneed parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) { if (eiClass == ElfHeader.EIClass.ELFCLASS32) { return new Verneed( Elf.Elf32.getElf32Half(buffer), Elf.Elf32.getElf32Half(buffer), Elf.Elf32.getElf32Word(buffer), Elf.Elf32.getElf32Word(buffer), Elf.Elf32.getElf32Word(buffer)); } else { return new Verneed( 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) vn_version); Elf.Elf32.putElf32Half(buffer, (short) vn_cnt); Elf.Elf32.putElf32Word(buffer, (int) vn_file); Elf.Elf32.putElf32Word(buffer, (int) vn_aux); Elf.Elf32.putElf32Word(buffer, (int) vn_next); } else { Elf.Elf64.putElf64Half(buffer, (short) vn_version); Elf.Elf64.putElf64Half(buffer, (short) vn_cnt); Elf.Elf64.putElf64Word(buffer, (int) vn_file); Elf.Elf64.putElf64Word(buffer, (int) vn_aux); Elf.Elf64.putElf64Word(buffer, (int) vn_next); } } } public static class Vernaux { private static final int BYTES = 16; // CHECKSTYLE.OFF: MemberName public final long vna_hash; public final int vna_flags; public final int vna_other; public final long vna_name; public final long vna_next; // CHECKSTYLE.ON: MemberName // CHECKSTYLE.OFF: ParameterName public Vernaux(long vna_hash, int vna_flags, int vna_other, long vna_name, long vna_next) { this.vna_hash = vna_hash; this.vna_flags = vna_flags; this.vna_other = vna_other; this.vna_name = vna_name; this.vna_next = vna_next; } // CHECKSTYLE.ON: ParameterName private static Vernaux parse(ElfHeader.EIClass eiClass, ByteBuffer buffer) { if (eiClass == ElfHeader.EIClass.ELFCLASS32) { return new Vernaux( Elf.Elf32.getElf32Word(buffer), Elf.Elf32.getElf32Half(buffer), Elf.Elf32.getElf32Half(buffer), Elf.Elf32.getElf32Word(buffer), Elf.Elf32.getElf32Word(buffer)); } else { return new Vernaux( Elf.Elf64.getElf64Word(buffer), Elf.Elf64.getElf64Half(buffer), Elf.Elf64.getElf64Half(buffer), 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) vna_hash); Elf.Elf32.putElf32Half(buffer, (short) vna_flags); Elf.Elf32.putElf32Half(buffer, (short) vna_other); Elf.Elf32.putElf32Word(buffer, (int) vna_name); Elf.Elf32.putElf32Word(buffer, (int) vna_next); } else { Elf.Elf64.putElf64Word(buffer, (int) vna_hash); Elf.Elf64.putElf64Half(buffer, (short) vna_flags); Elf.Elf64.putElf64Half(buffer, (short) vna_other); Elf.Elf64.putElf64Word(buffer, (int) vna_name); Elf.Elf64.putElf64Word(buffer, (int) vna_next); } } } }