//===- BTFParser.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// BTFParser reads .BTF and .BTF.ext ELF sections generated by LLVM
// BPF backend and provides introspection for the stored information.
// Currently the following information is accessible:
// - string table;
// - instruction offset to line information mapping;
// - types table;
// - CO-RE relocations table.
//
// See llvm/DebugInfo/BTF/BTF.h for some details about binary format
// and links to Linux Kernel documentation.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_BTF_BTFPARSER_H
#define LLVM_DEBUGINFO_BTF_BTFPARSER_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/DebugInfo/BTF/BTF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/DataExtractor.h"

namespace llvm {
using object::ObjectFile;
using object::SectionedAddress;
using object::SectionRef;

class BTFParser {
  using BTFLinesVector = SmallVector<BTF::BPFLineInfo, 0>;
  using BTFRelocVector = SmallVector<BTF::BPFFieldReloc, 0>;

  // In BTF strings are stored as a continuous memory region with
  // individual strings separated by 0 bytes. Strings are identified
  // by an offset in such region.
  // The `StringsTable` points to this region in the parsed ObjectFile.
  StringRef StringsTable;

  // A copy of types table from the object file but using native byte
  // order. Should not be too big in practice, e.g. for ~250MiB vmlinux
  // image it is ~4MiB.
  OwningArrayRef<uint8_t> TypesBuffer;

  // Maps ELF section number to instruction line number information.
  // Each BTFLinesVector is sorted by `InsnOffset` to allow fast lookups.
  DenseMap<uint64_t, BTFLinesVector> SectionLines;

  // Maps ELF section number to CO-RE relocation information.
  // Each BTFRelocVector is sorted by `InsnOffset` to allow fast lookups.
  DenseMap<uint64_t, BTFRelocVector> SectionRelocs;

  // Vector of pointers to all known types, index in this vector
  // equals to logical type BTF id.
  // Pointers point to memory owned by `TypesBuffer`
  // (except pointer at index 0, which is statically allocated).
  std::vector<const BTF::CommonType *> Types;

  struct ParseContext;
  Error parseBTF(ParseContext &Ctx, SectionRef BTF);
  Error parseBTFExt(ParseContext &Ctx, SectionRef BTFExt);
  Error parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
                      uint64_t LineInfoStart, uint64_t LineInfoEnd);
  Error parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor,
                       uint64_t RelocInfoStart, uint64_t RelocInfoEnd);
  Error parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
                       StringRef RawData);

public:
  // Looks-up a string in the .BTF section's string table.
  // Offset is relative to string table start.
  StringRef findString(uint32_t Offset) const;

  // Search for line information for a specific address,
  // address match is exact (contrary to DWARFContext).
  // Return nullptr if no information found.
  // If information is present, return a pointer to object
  // owned by this class.
  const BTF::BPFLineInfo *findLineInfo(SectionedAddress Address) const;

  // Search for CO-RE relocation information for a specific address.
  // Return nullptr if no information found.
  // If information is present, return a pointer to object
  // owned by this class.
  const BTF::BPFFieldReloc *findFieldReloc(SectionedAddress Address) const;

  // Return a human readable representation of the CO-RE relocation
  // record, this is for display purpose only.
  // See implementation for details.
  void symbolize(const BTF::BPFFieldReloc *Reloc,
                 SmallVectorImpl<char> &Result) const;

  // Lookup BTF type definition with a specific index.
  // Return nullptr if no information found.
  // If information is present, return a pointer to object
  // owned by this class.
  const BTF::CommonType *findType(uint32_t Id) const;

  // Return total number of known BTF types.
  size_t typesCount() const { return Types.size(); }

  // Allow to selectively load BTF information.
  struct ParseOptions {
    bool LoadLines = false;
    bool LoadTypes = false;
    bool LoadRelocs = false;
  };

  // Fills instance of BTFParser with information stored in .BTF and
  // .BTF.ext sections of the `Obj`. If this instance was already
  // filled, old data is discarded.
  //
  // If information cannot be parsed:
  // - return an error describing the failure;
  // - state of the BTFParser might be incomplete but is not invalid,
  //   queries might be run against it, but some (or all) information
  //   might be unavailable;
  Error parse(const ObjectFile &Obj, const ParseOptions &Opts);
  Error parse(const ObjectFile &Obj) { return parse(Obj, {true, true, true}); }

  // Return true if `Obj` has .BTF and .BTF.ext sections.
  static bool hasBTFSections(const ObjectFile &Obj);
};

} // namespace llvm

#endif // LLVM_DEBUGINFO_BTF_BTFPARSER_H
