Compiler projects using llvm
//===- NativeFunctionSymbol.cpp - info about function symbols----*- 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
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"

#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"

using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;

NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session,
                                           SymIndexId Id,
                                           const codeview::ProcSym &Sym,
                                           uint32_t Offset)
    : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym),
      RecordOffset(Offset) {}

NativeFunctionSymbol::~NativeFunctionSymbol() = default;

void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent,
                                PdbSymbolIdField ShowIdFields,
                                PdbSymbolIdField RecurseIdFields) const {
  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
  dumpSymbolField(OS, "name", getName(), Indent);
  dumpSymbolField(OS, "length", getLength(), Indent);
  dumpSymbolField(OS, "offset", getAddressOffset(), Indent);
  dumpSymbolField(OS, "section", getAddressSection(), Indent);
}

uint32_t NativeFunctionSymbol::getAddressOffset() const {
  return Sym.CodeOffset;
}

uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; }
std::string NativeFunctionSymbol::getName() const {
  return std::string(Sym.Name);
}

uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; }

uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
  return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
}

uint64_t NativeFunctionSymbol::getVirtualAddress() const {
  return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
}

static bool inlineSiteContainsAddress(InlineSiteSym &IS,
                                      uint32_t OffsetInFunc) {
  // Returns true if inline site contains the offset.
  bool Found = false;
  uint32_t CodeOffset = 0;
  for (auto &Annot : IS.annotations()) {
    switch (Annot.OpCode) {
    case BinaryAnnotationsOpCode::CodeOffset:
    case BinaryAnnotationsOpCode::ChangeCodeOffset:
    case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
      CodeOffset += Annot.U1;
      if (OffsetInFunc >= CodeOffset)
        Found = true;
      break;
    case BinaryAnnotationsOpCode::ChangeCodeLength:
      CodeOffset += Annot.U1;
      if (Found && OffsetInFunc < CodeOffset)
        return true;
      Found = false;
      break;
    case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
      CodeOffset += Annot.U2;
      if (OffsetInFunc >= CodeOffset && OffsetInFunc < CodeOffset + Annot.U1)
        return true;
      Found = false;
      break;
    default:
      break;
    }
  }
  return false;
}

std::unique_ptr<IPDBEnumSymbols>
NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const {
  uint16_t Modi;
  if (!Session.moduleIndexForVA(VA, Modi))
    return nullptr;

  Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
  if (!ModS) {
    consumeError(ModS.takeError());
    return nullptr;
  }
  CVSymbolArray Syms = ModS->getSymbolArray();

  // Search for inline sites. There should be one matching top level inline
  // site. Then search in its nested inline sites.
  std::vector<SymIndexId> Frames;
  uint32_t CodeOffset = VA - getVirtualAddress();
  auto Start = Syms.at(RecordOffset);
  auto End = Syms.at(Sym.End);
  while (Start != End) {
    bool Found = false;
    // Find matching inline site within Start and End.
    for (; Start != End; ++Start) {
      if (Start->kind() != S_INLINESITE)
        continue;

      InlineSiteSym IS =
          cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start));
      if (inlineSiteContainsAddress(IS, CodeOffset)) {
        // Insert frames in reverse order.
        SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol(
            IS, getVirtualAddress(), Modi, Start.offset());
        Frames.insert(Frames.begin(), Id);

        // Update offsets to search within this inline site.
        ++Start;
        End = Syms.at(IS.End);
        Found = true;
        break;
      }

      Start = Syms.at(IS.End);
      if (Start == End)
        break;
    }

    if (!Found)
      break;
  }

  return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames));
}