brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 46bdd6c Raw
248 lines · cpp
1//===-- CompileUnitIndex.cpp ----------------------------------------------===//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 "CompileUnitIndex.h"10 11#include "PdbIndex.h"12#include "PdbUtil.h"13 14#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"15#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"16#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"17#include "llvm/DebugInfo/MSF/MappedBlockStream.h"18#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"19#include "llvm/DebugInfo/PDB/Native/DbiStream.h"20#include "llvm/DebugInfo/PDB/Native/InfoStream.h"21#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"22#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"23#include "llvm/DebugInfo/PDB/Native/TpiStream.h"24#include "llvm/Support/Path.h"25 26#include "lldb/Utility/LLDBAssert.h"27 28using namespace lldb;29using namespace lldb_private;30using namespace lldb_private::npdb;31using namespace llvm::codeview;32using namespace llvm::pdb;33 34static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) {35  if (main == other)36    return true;37 38  // If the files refer to the local file system, we can just ask the file39  // system if they're equivalent.  But if the source isn't present on disk40  // then we still want to try.41  if (llvm::sys::fs::equivalent(main, other))42    return true;43 44  llvm::SmallString<64> normalized(other);45  llvm::sys::path::native(normalized);46  return main.equals_insensitive(normalized);47}48 49static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) {50  cci.m_compile_opts.emplace();51  llvm::cantFail(52      SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts));53}54 55static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) {56  cci.m_obj_name.emplace();57  llvm::cantFail(58      SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name));59}60 61static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym,62                           CompilandIndexItem &cci) {63  BuildInfoSym bis(SymbolRecordKind::BuildInfoSym);64  llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis));65 66  // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream.  Let's do67  // a little extra work to pull out the LF_BUILDINFO.68  LazyRandomTypeCollection &types = index.ipi().typeCollection();69  std::optional<CVType> cvt = types.tryGetType(bis.BuildId);70 71  if (!cvt || cvt->kind() != LF_BUILDINFO)72    return;73 74  BuildInfoRecord bir;75  llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir));76  cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end());77}78 79static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {80  const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray();81 82  // This is a private function, it shouldn't be called if the information83  // has already been parsed.84  lldbassert(!item.m_obj_name);85  lldbassert(!item.m_compile_opts);86  lldbassert(item.m_build_info.empty());87 88  // We're looking for 3 things.  S_COMPILE3, S_OBJNAME, and S_BUILDINFO.89  int found = 0;90  for (const CVSymbol &sym : syms) {91    switch (sym.kind()) {92    case S_COMPILE3:93      ParseCompile3(sym, item);94      break;95    case S_OBJNAME:96      ParseObjname(sym, item);97      break;98    case S_BUILDINFO:99      ParseBuildInfo(index, sym, item);100      break;101    default:102      continue;103    }104    if (++found >= 3)105      break;106  }107}108 109static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {110  for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {111    if (ss.kind() != DebugSubsectionKind::InlineeLines)112      continue;113 114    DebugInlineeLinesSubsectionRef inlinee_lines;115    llvm::BinaryStreamReader reader(ss.getRecordData());116    if (llvm::Error error = inlinee_lines.initialize(reader)) {117      consumeError(std::move(error));118      continue;119    }120 121    for (const InlineeSourceLine &Line : inlinee_lines) {122      item.m_inline_map[Line.Header->Inlinee] = Line;123    }124  }125}126 127CompilandIndexItem::CompilandIndexItem(128    PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,129    llvm::pdb::DbiModuleDescriptor descriptor)130    : m_id(id), m_debug_stream(std::move(debug_stream)),131      m_module_descriptor(std::move(descriptor)) {}132 133CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {134  auto result = m_comp_units.try_emplace(modi, nullptr);135  if (!result.second)136    return *result.first->second;137 138  // Find the module list and load its debug information stream and cache it139  // since we need to use it for almost all interesting operations.140  const DbiModuleList &modules = m_index.dbi().modules();141  llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);142  uint16_t stream = descriptor.getModuleStreamIndex();143  std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =144      m_index.pdb().createIndexedStream(stream);145 146 147  std::unique_ptr<CompilandIndexItem>& cci = result.first->second;148 149  if (!stream_data) {150    llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, nullptr);151    cci = std::make_unique<CompilandIndexItem>(PdbCompilandId{ modi }, debug_stream, std::move(descriptor));152    return *cci;153  }154 155  llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,156                                               std::move(stream_data));157 158  cantFail(debug_stream.reload());159 160  cci = std::make_unique<CompilandIndexItem>(161      PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));162  ParseExtendedInfo(m_index, *cci);163  ParseInlineeLineTableForCompileUnit(*cci);164 165  auto strings = m_index.pdb().getStringTable();166  if (strings) {167    cci->m_strings.initialize(cci->m_debug_stream.getSubsectionsArray());168    cci->m_strings.setStrings(strings->getStringTable());169  } else {170    consumeError(strings.takeError());171  }172 173  // We want the main source file to always comes first.  Note that we can't174  // just push_back the main file onto the front because `GetMainSourceFile`175  // computes it in such a way that it doesn't own the resulting memory.  So we176  // have to iterate the module file list comparing each one to the main file177  // name until we find it, and we can cache that one since the memory is backed178  // by a contiguous chunk inside the mapped PDB.179  llvm::SmallString<64> main_file = GetMainSourceFile(*cci);180  llvm::sys::path::native(main_file);181 182  uint32_t file_count = modules.getSourceFileCount(modi);183  cci->m_file_list.reserve(file_count);184  bool found_main_file = false;185  for (llvm::StringRef file : modules.source_files(modi)) {186    if (!found_main_file && IsMainFile(main_file, file)) {187      cci->m_file_list.insert(cci->m_file_list.begin(), file);188      found_main_file = true;189      continue;190    }191    cci->m_file_list.push_back(file);192  }193 194  return *cci;195}196 197const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {198  auto iter = m_comp_units.find(modi);199  if (iter == m_comp_units.end())200    return nullptr;201  return iter->second.get();202}203 204CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {205  auto iter = m_comp_units.find(modi);206  if (iter == m_comp_units.end())207    return nullptr;208  return iter->second.get();209}210 211llvm::SmallString<64>212CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {213  // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID214  // records in the IPI stream.  The order of the arg indices is as follows:215  // [0] - working directory where compiler was invoked.216  // [1] - absolute path to compiler binary217  // [2] - source file name218  // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets219  //       added even when using /Z7)220  // [4] - full command line invocation.221  //222  // We need to form the path [0]\[2] to generate the full path to the main223  // file.source224  if (item.m_build_info.size() < 3)225    return {""};226 227  LazyRandomTypeCollection &types = m_index.ipi().typeCollection();228 229  StringIdRecord working_dir;230  StringIdRecord file_name;231  CVType dir_cvt = types.getType(item.m_build_info[0]);232  CVType file_cvt = types.getType(item.m_build_info[2]);233  llvm::cantFail(234      TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));235  llvm::cantFail(236      TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));237 238  llvm::sys::path::Style style = working_dir.String.starts_with("/")239                                     ? llvm::sys::path::Style::posix240                                     : llvm::sys::path::Style::windows;241  if (llvm::sys::path::is_absolute(file_name.String, style))242    return file_name.String;243 244  llvm::SmallString<64> absolute_path = working_dir.String;245  llvm::sys::path::append(absolute_path, file_name.String);246  return absolute_path;247}248