// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

#include <string>
#include <vector>

#include <stout/os.hpp>
#include <stout/try.hpp>

#include "linux/ldcache.hpp"

using std::string;
using std::vector;

// There are two formats for ld.so.cache. The pre-glibc format 2.2
// listed the number of library entries, followed by the entries
// themselves, followed by a string table holding strings pointed
// to by the library entries. This format is summarized below:
//
//      HEADER_MAGIC_OLD
//      nlibs
//      libs[0]
//      ...
//      libs[nlibs-1]
//      first string\0second string\0...last string\0
//      ^                                           ^
//      start of string table     end of string table
//
// For glibc 2.2 and beyond, a new format was created so that each
// library entry could hold more meta-data about the libraries they
// reference. To preserve backwards compatibility, the new format was
// embedded in the old format inside its string table (simply moving
// all existing strings further down in the string table). This makes
// sense for backwards compatibility because code that could parse the
// old format still works (the offsets for strings pointed to by
// the library entries are just larger now).
//
// However, it adds complications when parsing for the new format
// because the new format header needs to be aligned on an 8 byte
// boundary (potentially pushing the start address of the string table
// down a few bytes). A summary of the new format embedded in the old
// format with annotations on the start address of the string table
// can be seen below:
//
//      HEADER_MAGIC_OLD
//      nlibs
//      libs[0]
//      ...
//      libs[nlibs-1]
//      pad (align for new format)
//      HEADER_MAGIC_NEW    <-- start of string table
//      nlibs
//      len_strings
//      unused    // 20 bytes reserved for extensions
//      libs[0]
//      ...
//      libs[nlibs-1]
//      first string\0second string\0...last string\0
//                                                  ^
//                                end of string table
//
// We currently only support the new format, since glibc 2.2
// was released in late 2000.

namespace ldcache {

constexpr char HEADER_MAGIC_OLD[] = "ld.so-1.7.0";
constexpr char HEADER_MAGIC_NEW[] = "glibc-ld.so.cache1.1";

#define IS_ELF  0x00000001


struct HeaderOld
{
  char magic[sizeof(HEADER_MAGIC_OLD) - 1];
  uint32_t libraryCount; // Number of library entries.
};


struct EntryOld
{
  int32_t flags;  // 0x01 indicates ELF library.
  uint32_t key;   // String table index.
  uint32_t value; // String table index.
};


struct HeaderNew
{
  char magic[sizeof(HEADER_MAGIC_NEW) - 1];
  uint32_t libraryCount;  // Number of library entries.
  uint32_t stringsLength; // Length of "actual" string table.
  uint32_t unused[5];     // Leave space for future extensions
                          // and align to 8 byte boundary.
};


struct EntryNew
{
  int32_t flags;        // Flags bits determine arch and library type.
  uint32_t key;         // String table index.
  uint32_t value;       // String table index.
  uint32_t osVersion;   // Required OS version.
  uint64_t hwcap;       // Hwcap entry.
};


// Returns a 'boundary' aligned pointer by rounding up to
// the nearest multiple of 'boundary'.
static inline const char* align(const char* address, size_t boundary)
{
  if ((size_t)address % boundary == 0) {
    return address;
  }
  return (address + boundary) - ((size_t)address % boundary);
}


Try<vector<Entry>> parse(const string& path)
{
  // Read the complete file into a buffer
  Try<string> buffer = os::read(path);
  if (buffer.isError()) {
    return Error(buffer.error());
  }

  const char* data = buffer->data();

  // Grab a pointer to the old format header (for verification of
  // HEADER_MAGIC_OLD later on). Then jump forward to the location of
  // the new format header (it is the only format we support).
  HeaderOld* headerOld = (HeaderOld*)data;
  data += sizeof(HeaderOld);
  if (data >= buffer->data() + buffer->size()) {
    return Error("Invalid format");
  }

  data += headerOld->libraryCount * sizeof(EntryOld);
  if (data >= buffer->data() + buffer->size()) {
    return Error("Invalid format");
  }

  // The new format header and all of its library entries are embedded
  // in the old format's string table (the current location of data).
  // However, the header is aligned on an 8 byte boundary, so we
  // need to align 'data' to get it to point to the new header.
  data = align(data, alignof(HeaderNew));
  if (data >= buffer->data() + buffer->size()) {
    return Error("Invalid format");
  }

  // Construct pointers to all of the important regions in the new
  // format: the header, the libentry array, and the new string table
  // (which starts at the same address as the aligned headerNew pointer).
  HeaderNew* headerNew = (HeaderNew*)data;
  data += sizeof(HeaderNew);
  if (data >= buffer->data() + buffer->size()) {
    return Error("Invalid format");
  }

  EntryNew* entriesNew = (EntryNew*)data;
  data += headerNew->libraryCount * sizeof(EntryNew);
  if (data >= buffer->data() + buffer->size()) {
    return Error("Invalid format");
  }

  // The start of the strings table is at the beginning of
  // the new header, per the above format description.
  char* strings = (char*)headerNew;

  // Adjust the pointer to add on the additional size of the strings
  // contained in the string table. At this point, 'data' should
  // point to an address just beyond the end of the file.
  data += headerNew->stringsLength;
  if ((size_t)(data - buffer->data()) != buffer->size()) {
    return Error("Invalid format");
  }

  // Validate our header magic.
  if (strncmp(headerOld->magic,
        HEADER_MAGIC_OLD,
        sizeof(HEADER_MAGIC_OLD) - 1) != 0) {
    return Error("Invalid format");
  }

  if (strncmp(headerNew->magic,
        HEADER_MAGIC_NEW,
        sizeof(HEADER_MAGIC_NEW) - 1) != 0) {
    return Error("Invalid format");
  }

  // Make sure the very last character in the buffer is a '\0'.
  // This way, no matter what strings we index in the string
  // table, we know they will never run beyond the end of the
  // file buffer when extracting them.
  if (*(data - 1) != '\0') {
    return Error("Invalid format");
  }

  // Build our vector of ldcache entries.
  vector<Entry> ldcache;
  for (uint32_t i = 0; i < headerNew->libraryCount; i++) {
    if (!(entriesNew[i].flags & IS_ELF)) {
      continue;
    }

    if (strings + entriesNew[i].key >= data) {
      return Error("Invalid format");
    }

    if (strings + entriesNew[i].value >= data) {
      return Error("Invalid format");
    }

    Entry entry;
    entry.name = &strings[entriesNew[i].key];
    entry.path = &strings[entriesNew[i].value];
    ldcache.push_back(entry);
  }

  return ldcache;
}

} // namespace ldcache {
