[llvm] a6d8a05 - Implement some functions in NativeSession.

Amy Huang via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 21 11:48:52 PDT 2020


Author: Amy Huang
Date: 2020-04-21T11:48:40-07:00
New Revision: a6d8a055e92eb4853805d1ad1be0b1a6523524ef

URL: https://github.com/llvm/llvm-project/commit/a6d8a055e92eb4853805d1ad1be0b1a6523524ef
DIFF: https://github.com/llvm/llvm-project/commit/a6d8a055e92eb4853805d1ad1be0b1a6523524ef.diff

LOG: Implement some functions in NativeSession.

Summary:
This change implements readFromExe, and calculating VA and RVA, which
are some of the functionalities that will be used for native PDB reading
for llvm symbolizer.

bug: https://bugs.llvm.org/show_bug.cgi?id=41795

Reviewers: hans, amccarth, rnk

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D78128

Added: 
    llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.cpp
    llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.exe
    llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.pdb
    llvm/unittests/DebugInfo/PDB/NativeSessionTest.cpp

Modified: 
    llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h
    llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
    llvm/lib/DebugInfo/PDB/PDB.cpp
    llvm/unittests/DebugInfo/PDB/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h
index ee7d8cdec93b..26b1992a03d7 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h
@@ -26,6 +26,11 @@ class PDBFile;
 class NativeExeSymbol;
 
 class NativeSession : public IPDBSession {
+  struct PdbSearchOptions {
+    StringRef ExePath;
+    // FIXME: Add other PDB search options (_NT_SYMBOL_PATH, symsrv)
+  };
+
 public:
   NativeSession(std::unique_ptr<PDBFile> PdbFile,
                 std::unique_ptr<BumpPtrAllocator> Allocator);
@@ -33,8 +38,11 @@ class NativeSession : public IPDBSession {
 
   static Error createFromPdb(std::unique_ptr<MemoryBuffer> MB,
                              std::unique_ptr<IPDBSession> &Session);
+  static Error createFromPdbPath(StringRef PdbPath,
+                                 std::unique_ptr<IPDBSession> &Session);
   static Error createFromExe(StringRef Path,
                              std::unique_ptr<IPDBSession> &Session);
+  static Expected<std::string> searchForPdb(const PdbSearchOptions &Opts);
 
   uint64_t getLoadAddress() const override;
   bool setLoadAddress(uint64_t Address) override;
@@ -109,6 +117,7 @@ class NativeSession : public IPDBSession {
 
   SymbolCache Cache;
   SymIndexId ExeSymbol = 0;
+  uint64_t LoadAddress = 0;
 };
 } // namespace pdb
 } // namespace llvm

diff  --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
index b45a5881dcb5..40b7c46dae26 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -12,6 +12,7 @@
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
 #include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
 #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
 #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
@@ -29,7 +30,10 @@
 #include "llvm/Support/BinaryByteStream.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/object/COFF.h"
 
 #include <algorithm>
 #include <cassert>
@@ -75,14 +79,112 @@ Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,
   return Error::success();
 }
 
-Error NativeSession::createFromExe(StringRef Path,
+static Expected<std::unique_ptr<PDBFile>>
+loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+      MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
+                            /*RequiresNullTerminator=*/false);
+  if (!ErrorOrBuffer)
+    return make_error<RawError>(ErrorOrBuffer.getError());
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+
+  PdbPath = Buffer->getBufferIdentifier();
+  file_magic Magic;
+  auto EC = identify_magic(PdbPath, Magic);
+  if (EC || Magic != file_magic::pdb)
+    return make_error<RawError>(EC);
+
+  auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer),
+                                                         llvm::support::little);
+
+  auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
+  if (auto EC = File->parseFileHeaders())
+    return std::move(EC);
+
+  if (auto EC = File->parseStreamData())
+    return std::move(EC);
+
+  return File;
+}
+
+Error NativeSession::createFromPdbPath(StringRef PdbPath,
+                                       std::unique_ptr<IPDBSession> &Session) {
+  auto Allocator = std::make_unique<BumpPtrAllocator>();
+  auto PdbFile = loadPdbFile(PdbPath, Allocator);
+  if (!PdbFile)
+    return PdbFile.takeError();
+
+  Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),
+                                            std::move(Allocator));
+  return Error::success();
+}
+
+static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {
+  Expected<object::OwningBinary<object::Binary>> BinaryFile =
+      object::createBinary(ExePath);
+  if (!BinaryFile)
+    return BinaryFile.takeError();
+
+  const object::COFFObjectFile *ObjFile =
+      dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());
+  if (!ObjFile)
+    return make_error<RawError>(raw_error_code::invalid_format);
+
+  StringRef PdbPath;
+  const llvm::codeview::DebugInfo *PdbInfo = nullptr;
+  if (auto EC = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
+    return make_error<RawError>(EC);
+
+  return std::string(PdbPath);
+}
+
+Error NativeSession::createFromExe(StringRef ExePath,
                                    std::unique_ptr<IPDBSession> &Session) {
-  return make_error<RawError>(raw_error_code::feature_unsupported);
+  Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
+  if (!PdbPath)
+    return PdbPath.takeError();
+
+  file_magic Magic;
+  auto EC = identify_magic(PdbPath.get(), Magic);
+  if (EC || Magic != file_magic::pdb)
+    return make_error<RawError>(EC);
+
+  auto Allocator = std::make_unique<BumpPtrAllocator>();
+  auto File = loadPdbFile(PdbPath.get(), Allocator);
+  if (!File)
+    return File.takeError();
+
+  Session = std::make_unique<NativeSession>(std::move(File.get()),
+                                            std::move(Allocator));
+
+  return Error::success();
 }
 
-uint64_t NativeSession::getLoadAddress() const { return 0; }
+Expected<std::string>
+NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
+  Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);
+  if (!PathOrErr)
+    return PathOrErr.takeError();
+  StringRef PdbName = sys::path::filename(PathOrErr.get());
 
-bool NativeSession::setLoadAddress(uint64_t Address) { return false; }
+  // Check if pdb exists in the executable directory.
+  SmallString<128> PdbPath = StringRef(Opts.ExePath);
+  sys::path::remove_filename(PdbPath);
+  sys::path::append(PdbPath, PdbName);
+
+  auto Allocator = std::make_unique<BumpPtrAllocator>();
+  if (loadPdbFile(PdbPath, Allocator))
+    return std::string(PdbPath);
+
+  return make_error<RawError>("PDB not found");
+}
+
+uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
+
+bool NativeSession::setLoadAddress(uint64_t Address) {
+  LoadAddress = Address;
+  return true;
+}
 
 std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
   return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
@@ -95,12 +197,30 @@ NativeSession::getSymbolById(SymIndexId SymbolId) const {
 
 bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,
                                  uint32_t &Offset) const {
-  return false;
+  uint32_t RVA = VA - getLoadAddress();
+  return addressForRVA(RVA, Section, Offset);
 }
 
-bool NativeSession::addressForRVA(uint32_t VA, uint32_t &Section,
+bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
                                   uint32_t &Offset) const {
-  return false;
+  auto Dbi = Pdb->getPDBDbiStream();
+  if (!Dbi)
+    return false;
+
+  Section = 0;
+  Offset = 0;
+
+  if ((int32_t)RVA < 0)
+    return true;
+
+  Offset = RVA;
+  for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
+    auto &Sec = Dbi->getSectionHeaders()[Section];
+    if (RVA < Sec.VirtualAddress)
+      return true;
+    Offset = RVA - Sec.VirtualAddress;
+  }
+  return true;
 }
 
 std::unique_ptr<PDBSymbol>

diff  --git a/llvm/lib/DebugInfo/PDB/PDB.cpp b/llvm/lib/DebugInfo/PDB/PDB.cpp
index e7b968cb7bea..a0d015c7839e 100644
--- a/llvm/lib/DebugInfo/PDB/PDB.cpp
+++ b/llvm/lib/DebugInfo/PDB/PDB.cpp
@@ -23,15 +23,8 @@ using namespace llvm::pdb;
 Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path,
                                 std::unique_ptr<IPDBSession> &Session) {
   // Create the correct concrete instance type based on the value of Type.
-  if (Type == PDB_ReaderType::Native) {
-    ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
-        MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
-                                     /*RequiresNullTerminator=*/false);
-    if (!ErrorOrBuffer)
-      return errorCodeToError(ErrorOrBuffer.getError());
-
-    return NativeSession::createFromPdb(std::move(*ErrorOrBuffer), Session);
-  }
+  if (Type == PDB_ReaderType::Native)
+    return NativeSession::createFromPdbPath(Path, Session);
 
 #if LLVM_ENABLE_DIA_SDK
   return DIASession::createFromPdb(Path, Session);
@@ -43,8 +36,17 @@ Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path,
 Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path,
                                 std::unique_ptr<IPDBSession> &Session) {
   // Create the correct concrete instance type based on the value of Type.
-  if (Type == PDB_ReaderType::Native)
-    return NativeSession::createFromExe(Path, Session);
+  if (Type == PDB_ReaderType::Native) {
+    if (auto Err = NativeSession::createFromExe(Path, Session)) {
+      consumeError(std::move(Err));
+
+      Expected<std::string> PdbPath = NativeSession::searchForPdb({Path});
+      if (!PdbPath)
+        return PdbPath.takeError();
+      return NativeSession::createFromPdbPath(PdbPath.get(), Session);
+    }
+    return Error::success();
+  }
 
 #if LLVM_ENABLE_DIA_SDK
   return DIASession::createFromExe(Path, Session);

diff  --git a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
index 4edfd50c148d..c8c2659277a6 100644
--- a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest_with_input_files(DebugInfoPDBTests
   HashTableTest.cpp
+  NativeSessionTest.cpp
   NativeSymbolReuseTest.cpp
   StringTableBuilderTest.cpp
   PDBApiTest.cpp

diff  --git a/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.cpp b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.cpp
new file mode 100644
index 000000000000..5cd4030802c6
--- /dev/null
+++ b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.cpp
@@ -0,0 +1,4 @@
+// Compile with "cl /c /Zi SimpleTest.cpp"
+// Link with "link SimpleTest.obj /debug /nodefaultlib /entry:main"
+
+int main() { return 0; }

diff  --git a/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.exe b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.exe
new file mode 100644
index 000000000000..35ae9e2682b8
Binary files /dev/null and b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.exe 
diff er

diff  --git a/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.pdb b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.pdb
new file mode 100644
index 000000000000..30d00850488e
Binary files /dev/null and b/llvm/unittests/DebugInfo/PDB/Inputs/SimpleTest.pdb 
diff er

diff  --git a/llvm/unittests/DebugInfo/PDB/NativeSessionTest.cpp b/llvm/unittests/DebugInfo/PDB/NativeSessionTest.cpp
new file mode 100644
index 000000000000..8d27389c78d7
--- /dev/null
+++ b/llvm/unittests/DebugInfo/PDB/NativeSessionTest.cpp
@@ -0,0 +1,93 @@
+//===- llvm/unittest/DebugInfo/PDB/NativeSessionTest.cpp ------------------===//
+//
+// 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/NativeSession.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/Support/Path.h"
+
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+extern const char *TestMainArgv0;
+
+static std::string getExePath() {
+  SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
+  llvm::sys::path::append(InputsDir, "SimpleTest.exe");
+  return std::string(InputsDir);
+}
+
+TEST(NativeSessionTest, TestCreateFromExe) {
+  std::unique_ptr<IPDBSession> S;
+  Error E = pdb::loadDataForEXE(PDB_ReaderType::Native, getExePath(), S);
+  ASSERT_THAT_ERROR(std::move(E), Succeeded());
+}
+
+TEST(NativeSessionTest, TestSetLoadAddress) {
+  std::unique_ptr<IPDBSession> S;
+  Error E = pdb::loadDataForEXE(PDB_ReaderType::Native, getExePath(), S);
+  ASSERT_THAT_ERROR(std::move(E), Succeeded());
+
+  S->setLoadAddress(123);
+  EXPECT_EQ(S->getLoadAddress(), 123U);
+}
+
+TEST(NativeSessionTest, TestAddressForVA) {
+  std::unique_ptr<IPDBSession> S;
+  Error E = pdb::loadDataForEXE(PDB_ReaderType::Native, getExePath(), S);
+  ASSERT_THAT_ERROR(std::move(E), Succeeded());
+
+  uint64_t LoadAddr = S->getLoadAddress();
+  uint32_t Section;
+  uint32_t Offset;
+  ASSERT_TRUE(S->addressForVA(LoadAddr + 5000, Section, Offset));
+  EXPECT_EQ(1U, Section);
+  EXPECT_EQ(904U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(-1, Section, Offset));
+  EXPECT_EQ(0U, Section);
+  EXPECT_EQ(0U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(4, Section, Offset));
+  EXPECT_EQ(0U, Section);
+  EXPECT_EQ(4U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(LoadAddr + 100000, Section, Offset));
+  EXPECT_EQ(3U, Section);
+  EXPECT_EQ(83616U, Offset);
+}
+
+TEST(NativeSessionTest, TestAddressForRVA) {
+  std::unique_ptr<IPDBSession> S;
+  Error E = pdb::loadDataForEXE(PDB_ReaderType::Native, getExePath(), S);
+  ASSERT_THAT_ERROR(std::move(E), Succeeded());
+
+  uint32_t Section;
+  uint32_t Offset;
+  ASSERT_TRUE(S->addressForVA(5000, Section, Offset));
+  EXPECT_EQ(1U, Section);
+  EXPECT_EQ(904U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(-1, Section, Offset));
+  EXPECT_EQ(0U, Section);
+  EXPECT_EQ(0U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(4, Section, Offset));
+  EXPECT_EQ(0U, Section);
+  EXPECT_EQ(4U, Offset);
+
+  ASSERT_TRUE(S->addressForVA(100000, Section, Offset));
+  EXPECT_EQ(3U, Section);
+  EXPECT_EQ(83616U, Offset);
+}


        


More information about the llvm-commits mailing list