com.facebook.buck.cxx.AbstractElfExtractSectionsStep.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.cxx.AbstractElfExtractSectionsStep.java

Source

/*
 * 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;

import static java.nio.channels.FileChannel.MapMode.READ_ONLY;

import com.facebook.buck.cxx.elf.Elf;
import com.facebook.buck.cxx.elf.ElfSection;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.shell.DefaultShellStep;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.StepExecutionResult;
import com.facebook.buck.util.immutables.BuckStyleTuple;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import org.immutables.value.Value;

import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

/**
 * A step which extracts specific sections from an ELF file and compacts them into a new ELF file.
 */
@Value.Immutable
@BuckStyleTuple
abstract class AbstractElfExtractSectionsStep implements Step {

    abstract ProjectFilesystem getFilesystem();

    abstract ImmutableList<String> getObjcopyPrefix();

    abstract Path getInput();

    abstract Path getOutput();

    abstract ImmutableSet<String> getSections();

    // We want to compact the sections into the new ELF file, so find out the new addresses of each
    // section.
    private ImmutableMap<String, Long> getNewSectionAddresses() throws IOException {
        ImmutableMap.Builder<String, Long> addresses = ImmutableMap.builder();
        try (FileChannel channel = FileChannel.open(getFilesystem().resolve(getInput()), StandardOpenOption.READ)) {
            MappedByteBuffer buffer = channel.map(READ_ONLY, 0, channel.size());
            Elf elf = new Elf(buffer);

            // We start placing sections right after the program headers.
            long end = elf.header.e_phoff + elf.header.e_phnum * elf.header.e_phentsize;
            for (int index = 0; index < elf.getNumberOfSections(); index++) {
                ElfSection section = elf.getSectionByIndex(index);
                String name = elf.getSectionName(section.header);
                // If this is a target section, assign it the current address, then increment the next
                // address by this sections size.
                if (getSections().contains(name)) {
                    addresses.put(name, end);
                    end += section.header.sh_size;
                }
            }
        }
        return addresses.build();
    }

    private ImmutableList<String> getObjcopyCommand(ImmutableMap<String, Long> addresses) {
        ImmutableList.Builder<String> args = ImmutableList.builder();
        args.addAll(getObjcopyPrefix());
        for (String section : getSections()) {
            Long address = addresses.get(section);
            if (address != null) {
                args.add("--only-section", section, "--change-section-address",
                        String.format("%s=0x%x", section, address));
            }
        }
        args.add(getInput().toString());
        args.add(getOutput().toString());
        return args.build();
    }

    @Override
    public StepExecutionResult execute(ExecutionContext context) throws IOException, InterruptedException {
        ImmutableMap<String, Long> addresses = getNewSectionAddresses();
        Step objcopy = new DefaultShellStep(getFilesystem().getRootPath(), /* args */ getObjcopyCommand(addresses),
                /* env */ ImmutableMap.of());
        return objcopy.execute(context);
    }

    @Override
    public final String getShortName() {
        return "scrub_symbol_table";
    }

    @Override
    public String getDescription(ExecutionContext context) {
        return String.format("Extract sections %s from %s", Joiner.on(", ").join(getSections()), getInput());
    }

}