brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 4af8d30 Raw
247 lines · cpp
1//===- CallSiteInfo.cpp -----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/GSYM/CallSiteInfo.h"10#include "llvm/DebugInfo/GSYM/FileWriter.h"11#include "llvm/DebugInfo/GSYM/FunctionInfo.h"12#include "llvm/DebugInfo/GSYM/GsymCreator.h"13#include "llvm/MC/StringTableBuilder.h"14#include "llvm/Support/DataExtractor.h"15#include "llvm/Support/InterleavedRange.h"16#include "llvm/Support/YAMLParser.h"17#include "llvm/Support/YAMLTraits.h"18#include "llvm/Support/raw_ostream.h"19#include <string>20#include <vector>21 22using namespace llvm;23using namespace gsym;24 25Error CallSiteInfo::encode(FileWriter &O) const {26  O.writeU64(ReturnOffset);27  O.writeU8(Flags);28  O.writeU32(MatchRegex.size());29  for (uint32_t Entry : MatchRegex)30    O.writeU32(Entry);31  return Error::success();32}33 34Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,35                                            uint64_t &Offset) {36  CallSiteInfo CSI;37 38  // Read ReturnOffset39  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))40    return createStringError(std::errc::io_error,41                             "0x%8.8" PRIx64 ": missing ReturnOffset", Offset);42  CSI.ReturnOffset = Data.getU64(&Offset);43 44  // Read Flags45  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint8_t)))46    return createStringError(std::errc::io_error,47                             "0x%8.8" PRIx64 ": missing Flags", Offset);48  CSI.Flags = Data.getU8(&Offset);49 50  // Read number of MatchRegex entries51  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))52    return createStringError(std::errc::io_error,53                             "0x%8.8" PRIx64 ": missing MatchRegex count",54                             Offset);55  uint32_t NumEntries = Data.getU32(&Offset);56 57  CSI.MatchRegex.reserve(NumEntries);58  for (uint32_t i = 0; i < NumEntries; ++i) {59    if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))60      return createStringError(std::errc::io_error,61                               "0x%8.8" PRIx64 ": missing MatchRegex entry",62                               Offset);63    uint32_t Entry = Data.getU32(&Offset);64    CSI.MatchRegex.push_back(Entry);65  }66 67  return CSI;68}69 70Error CallSiteInfoCollection::encode(FileWriter &O) const {71  O.writeU32(CallSites.size());72  for (const CallSiteInfo &CSI : CallSites)73    if (Error Err = CSI.encode(O))74      return Err;75 76  return Error::success();77}78 79Expected<CallSiteInfoCollection>80CallSiteInfoCollection::decode(DataExtractor &Data) {81  CallSiteInfoCollection CSC;82  uint64_t Offset = 0;83 84  // Read number of CallSiteInfo entries85  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))86    return createStringError(std::errc::io_error,87                             "0x%8.8" PRIx64 ": missing CallSiteInfo count",88                             Offset);89  uint32_t NumCallSites = Data.getU32(&Offset);90 91  CSC.CallSites.reserve(NumCallSites);92  for (uint32_t i = 0; i < NumCallSites; ++i) {93    Expected<CallSiteInfo> ECSI = CallSiteInfo::decode(Data, Offset);94    if (!ECSI)95      return ECSI.takeError();96    CSC.CallSites.emplace_back(*ECSI);97  }98 99  return CSC;100}101 102/// Structures necessary for reading CallSiteInfo from YAML.103namespace llvm {104namespace yaml {105 106struct CallSiteYAML {107  // The offset of the return address of the call site - relative to the start108  // of the function.109  Hex64 return_offset;110  std::vector<std::string> match_regex;111  std::vector<std::string> flags;112};113 114struct FunctionYAML {115  std::string name;116  std::vector<CallSiteYAML> callsites;117};118 119struct FunctionsYAML {120  std::vector<FunctionYAML> functions;121};122 123template <> struct MappingTraits<CallSiteYAML> {124  static void mapping(IO &io, CallSiteYAML &callsite) {125    io.mapRequired("return_offset", callsite.return_offset);126    io.mapRequired("match_regex", callsite.match_regex);127    io.mapOptional("flags", callsite.flags);128  }129};130 131template <> struct MappingTraits<FunctionYAML> {132  static void mapping(IO &io, FunctionYAML &func) {133    io.mapRequired("name", func.name);134    io.mapOptional("callsites", func.callsites);135  }136};137 138template <> struct MappingTraits<FunctionsYAML> {139  static void mapping(IO &io, FunctionsYAML &FuncYAMLs) {140    io.mapRequired("functions", FuncYAMLs.functions);141  }142};143 144} // namespace yaml145} // namespace llvm146 147LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)148LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)149 150Error CallSiteInfoLoader::loadYAML(StringRef YAMLFile) {151  // Step 1: Read YAML file152  auto BufferOrError = MemoryBuffer::getFile(YAMLFile, /*IsText=*/true);153  if (!BufferOrError)154    return errorCodeToError(BufferOrError.getError());155 156  std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);157 158  // Step 2: Parse YAML content159  yaml::FunctionsYAML FuncsYAML;160  yaml::Input Yin(Buffer->getMemBufferRef());161  Yin >> FuncsYAML;162  if (Yin.error())163    return createStringError(Yin.error(), "Error parsing YAML file: %s\n",164                             Buffer->getBufferIdentifier().str().c_str());165 166  // Step 3: Build function map from Funcs167  auto FuncMap = buildFunctionMap();168 169  // Step 4: Process parsed YAML functions and update FuncMap170  return processYAMLFunctions(FuncsYAML, FuncMap);171}172 173StringMap<FunctionInfo *> CallSiteInfoLoader::buildFunctionMap() {174  // If the function name is already in the map, don't update it. This way we175  // preferentially use the first encountered function. Since symbols are176  // loaded from dSYM first, we end up preferring keeping track of symbols177  // from dSYM rather than from the symbol table - which is what we want to178  // do.179  StringMap<FunctionInfo *> FuncMap;180  for (auto &Func : Funcs) {181    FuncMap.try_emplace(GCreator.getString(Func.Name), &Func);182    if (auto &MFuncs = Func.MergedFunctions)183      for (auto &MFunc : MFuncs->MergedFunctions)184        FuncMap.try_emplace(GCreator.getString(MFunc.Name), &MFunc);185  }186  return FuncMap;187}188 189Error CallSiteInfoLoader::processYAMLFunctions(190    const yaml::FunctionsYAML &FuncYAMLs, StringMap<FunctionInfo *> &FuncMap) {191  // For each function in the YAML file192  for (const auto &FuncYAML : FuncYAMLs.functions) {193    auto It = FuncMap.find(FuncYAML.name);194    if (It == FuncMap.end())195      return createStringError(196          std::errc::invalid_argument,197          "Can't find function '%s' specified in callsite YAML\n",198          FuncYAML.name.c_str());199 200    FunctionInfo *FuncInfo = It->second;201    // Create a CallSiteInfoCollection if not already present202    if (!FuncInfo->CallSites)203      FuncInfo->CallSites = CallSiteInfoCollection();204    for (const auto &CallSiteYAML : FuncYAML.callsites) {205      CallSiteInfo CSI;206      // Since YAML has specifies relative return offsets, add the function207      // start address to make the offset absolute.208      CSI.ReturnOffset = CallSiteYAML.return_offset;209      for (const auto &Regex : CallSiteYAML.match_regex) {210        uint32_t StrOffset = GCreator.insertString(Regex);211        CSI.MatchRegex.push_back(StrOffset);212      }213 214      // Parse flags and combine them215      for (const auto &FlagStr : CallSiteYAML.flags) {216        if (FlagStr == "InternalCall") {217          CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::InternalCall);218        } else if (FlagStr == "ExternalCall") {219          CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::ExternalCall);220        } else {221          return createStringError(std::errc::invalid_argument,222                                   "Unknown flag in callsite YAML: %s\n",223                                   FlagStr.c_str());224        }225      }226      FuncInfo->CallSites->CallSites.push_back(CSI);227    }228  }229  return Error::success();230}231 232raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {233  OS << "  Return=" << HEX64(CSI.ReturnOffset);234  OS << "  Flags=" << HEX8(CSI.Flags);235  OS << "  RegEx=" << llvm::interleaved(CSI.MatchRegex, ",");236  return OS;237}238 239raw_ostream &gsym::operator<<(raw_ostream &OS,240                              const CallSiteInfoCollection &CSIC) {241  for (const auto &CS : CSIC.CallSites) {242    OS << CS;243    OS << "\n";244  }245  return OS;246}247