k13-engineering/node-elf-file

View on GitHub
lib/layout.js

Summary

Maintainability
D
1 day
Test Coverage
/* eslint-disable camelcase */
import assert from "assert";
import structureFactory from "./structures.js";

const prepareFileHeader = ({ data, structure }) => {
  let e_ehsize = data.file.e_ehsize || BigInt(structure.FileHeader.length);
  assert(e_ehsize >= BigInt(structure.FileHeader.length), "e_ehsize must not be smaller than minimal header size");

  return {
    e_ehsize
  };
};

const prepareProgramHeader = ({ data, structure }) => {
  let e_phentsize = data.file.e_phentsize || BigInt(structure.ProgramHeaderEntry.length);
  let e_phnum = data.file.e_phnum || BigInt(data.segments.length);

  assert(e_phentsize >= BigInt(structure.ProgramHeaderEntry.length), "e_phentsize must no be smaller than minimal entry size");
  assert(e_phnum === BigInt(data.segments.length), "e_phnum if given must match segments array length");

  return {
    e_phentsize,
    e_phnum
  };
};

const prepareSectionHeader = ({ data, structure }) => {
  let e_shentsize = data.file.e_shentsize || BigInt(structure.SectionHeaderEntry.length);
  let e_shnum = data.file.e_shnum || BigInt(data.sections.length);

  assert(e_shentsize >= BigInt(structure.ProgramHeaderEntry.length), "e_shentsize must no be smaller than minimal entry size");
  assert(e_shnum === BigInt(data.sections.length), "e_shnum if given must match sections array length");

  return {
    e_shentsize,
    e_shnum
  };
};

const copyExcluding = (data, excludes) => {
  let result = {};
  Object.keys(data).filter((key) => excludes.indexOf(key) < 0).forEach((key) => {
    result = Object.assign(result, {
      [key]: data[key]
    });
  });
  return result;
};

const delayout = (data) => {
  const file = copyExcluding(data.file, [
    "e_ehsize",

    "e_phoff",
    "e_phentsize",
    "e_phnum",

    "e_shoff",
    "e_shentsize",
    "e_shnum"
  ]);

  const segments = data.segments.map((segment) => copyExcluding(segment, [
    "p_offset"
  ]));

  const sections = data.sections.map((section) => copyExcluding(section, [
    "sh_offset"
  ]));

  const chunks = data.chunks.map((chunk) => copyExcluding(chunk, [
    "address"
  ]));

  return {
    file,
    segments,
    sections,
    chunks
  };
};

// phentsize may be set! phnum may not contradict
const layout = (data) => {
  const structure = structureFactory.create({ "ei_class": data.file.ei_class, "ei_data": data.file.ei_data });

  const { e_ehsize } = prepareFileHeader({ data, structure });
  const { e_phentsize, e_phnum } = prepareProgramHeader({ data, structure });
  const { e_shentsize, e_shnum } = prepareSectionHeader({ data, structure });

  const e_phoff = e_ehsize;
  const e_shoff = e_ehsize + e_phentsize * e_phnum;

  const file = Object.assign({}, data.file, {
    e_ehsize,
    e_phoff,
    e_phentsize,
    e_phnum,
    e_shoff,
    e_shentsize,
    e_shnum
  });

  let offset = e_shoff + e_shentsize * e_shnum;

  const chunks = data.chunks.map((chunk) => {
    const result = {
      "address": offset,
      "size": chunk.size,
      "data": chunk.data.slice(0)
    };

    offset += BigInt(chunk.data.length);

    return result;
  });

  const resolveOffset = (s) => {
    if (s.chunk_idx !== undefined) {
      const chunk = chunks[s.chunk_idx];
      assert(!!chunk, "referenced chunk not available");
      return chunk.address + s.chunk_offset;
    } else {
      return BigInt(0);
    }
  };

  const segments = data.segments.map((segment) => {
    return Object.assign({}, segment, {
      "p_offset": resolveOffset(segment)
    });
  });

  const sections = data.sections.map((section) => {
    return Object.assign({}, section, {
      "sh_offset": resolveOffset(section)
    });
  });

  return {
    file,
    segments,
    sections,
    chunks
  };
};

const xy = {
  layout,
  delayout
};

export default xy;