Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h
===================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PDBFile.h
@@ -25,6 +25,7 @@
 class DbiStream;
 class InfoStream;
 class PublicsStream;
+class SymbolStream;
 class TpiStream;
 
 class PDBFile {
@@ -64,6 +65,7 @@
   Expected<DbiStream &> getPDBDbiStream();
   Expected<TpiStream &> getPDBTpiStream();
   Expected<PublicsStream &> getPDBPublicsStream();
+  Expected<SymbolStream &> getPDBSymbolStream();
 
 private:
   std::unique_ptr<PDBFileContext> Context;
@@ -71,6 +73,7 @@
   std::unique_ptr<DbiStream> Dbi;
   std::unique_ptr<TpiStream> Tpi;
   std::unique_ptr<PublicsStream> Publics;
+  std::unique_ptr<SymbolStream> Symbols;
 };
 }
 }
Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h
===================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h
@@ -20,12 +20,13 @@
 
 namespace llvm {
 namespace pdb {
+class DbiStream;
 class PDBFile;
 
 class PublicsStream {
-  struct HeaderInfo;
   struct GSIHashHeader;
-  struct HRFile;
+  struct HashRecord;
+  struct HeaderInfo;
 
 public:
   PublicsStream(PDBFile &File, uint32_t StreamNum);
@@ -36,15 +37,21 @@
   uint32_t getSymHash() const;
   uint32_t getAddrMap() const;
   uint32_t getNumBuckets() const { return NumBuckets; }
+  std::vector<std::string> getSymbols() const;
   ArrayRef<uint32_t> getHashBuckets() const { return HashBuckets; }
   ArrayRef<uint32_t> getAddressMap() const { return AddressMap; }
   ArrayRef<uint32_t> getThunkMap() const { return ThunkMap; }
   ArrayRef<uint32_t> getSectionOffsets() const { return SectionOffsets; }
 
 private:
+  Error readSymbols();
+
+  PDBFile &Pdb;
+
   uint32_t StreamNum;
   MappedBlockStream Stream;
   uint32_t NumBuckets = 0;
+  std::vector<HashRecord> HashRecords;
   std::vector<uint32_t> HashBuckets;
   std::vector<uint32_t> AddressMap;
   std::vector<uint32_t> ThunkMap;
Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h
===================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h
@@ -0,0 +1,39 @@
+//===- SymbolStream.cpp - PDB Symbol Stream Access --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H
+#define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H
+
+#include "llvm/DebugInfo/CodeView/TypeStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/DebugInfo/PDB/Raw/ByteStream.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+
+class SymbolStream {
+public:
+  SymbolStream(PDBFile &File, uint32_t StreamNum);
+  ~SymbolStream();
+  Error reload();
+
+  Expected<std::string> getSymbolName(uint32_t Offset) const;
+
+private:
+  MappedBlockStream Stream;
+};
+}
+}
+
+#endif
Index: llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
===================================================================
--- llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
+++ llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
@@ -41,6 +41,7 @@
   Raw/RawError.cpp
   Raw/RawSession.cpp
   Raw/StreamReader.cpp
+  Raw/SymbolStream.cpp
   Raw/TpiStream.cpp)
 
 list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB")
Index: llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFile.cpp
===================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFile.cpp
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/PDBFile.cpp
@@ -13,6 +13,7 @@
 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -307,3 +308,17 @@
   }
   return *Publics;
 }
+
+Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
+  if (!Symbols) {
+    auto DbiS = getPDBDbiStream();
+    if (auto EC = DbiS.takeError())
+      return std::move(EC);
+    uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
+
+    Symbols.reset(new SymbolStream(*this, SymbolStreamNum));
+    if (auto EC = Symbols->reload())
+      return std::move(EC);
+  }
+  return *Symbols;
+}
Index: llvm/trunk/lib/DebugInfo/PDB/Raw/PublicsStream.cpp
===================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/PublicsStream.cpp
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/PublicsStream.cpp
@@ -27,9 +27,11 @@
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
 #include "llvm/DebugInfo/PDB/Raw/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
 
 #include "llvm/ADT/BitVector.h"
 #include "llvm/Support/Endian.h"
@@ -56,8 +58,7 @@
   ulittle32_t NumSections;
 };
 
-
-// This is GSIHashHdr struct defined in
+// This is GSIHashHdr.
 struct PublicsStream::GSIHashHeader {
   enum : unsigned {
     HdrSignature = ~0U,
@@ -69,8 +70,9 @@
   ulittle32_t NumBuckets;
 };
 
-struct PublicsStream::HRFile {
-  ulittle32_t Off;
+// This is HRFile.
+struct PublicsStream::HashRecord {
+  ulittle32_t Off; // Offset in the symbol record stream
   ulittle32_t CRef;
 };
 
@@ -84,7 +86,7 @@
 }
 
 PublicsStream::PublicsStream(PDBFile &File, uint32_t StreamNum)
-    : StreamNum(StreamNum), Stream(StreamNum, File) {}
+    : Pdb(File), StreamNum(StreamNum), Stream(StreamNum, File) {}
 
 PublicsStream::~PublicsStream() {}
 
@@ -114,12 +116,12 @@
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Publics Stream does not contain a header.");
 
-  // An array of HRFile follows. Read them.
-  if (HashHdr->HrSize % sizeof(HRFile))
+  // An array of HashRecord follows. Read them.
+  if (HashHdr->HrSize % sizeof(HashRecord))
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Invalid HR array size.");
-  std::vector<HRFile> HRs(HashHdr->HrSize / sizeof(HRFile));
-  if (auto EC = Reader.readArray<HRFile>(HRs))
+  HashRecords.resize(HashHdr->HrSize / sizeof(HashRecord));
+  if (auto EC = Reader.readArray<HashRecord>(HashRecords))
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Could not read an HR array");
 
@@ -178,3 +180,20 @@
                                 "Corrupted publics stream.");
   return Error::success();
 }
+
+std::vector<std::string> PublicsStream::getSymbols() const {
+  auto SymbolS = Pdb.getPDBSymbolStream();
+  if (SymbolS.takeError())
+    return {};
+  SymbolStream &SS = SymbolS.get();
+
+  std::vector<std::string> Ret;
+  for (const HashRecord &HR : HashRecords) {
+    // For some reason, symbol offset is biased by one.
+    Expected<std::string> Name = SS.getSymbolName(HR.Off - 1);
+    if (Name.takeError())
+      return Ret;
+    Ret.push_back(std::move(Name.get()));
+  }
+  return Ret;
+}
Index: llvm/trunk/lib/DebugInfo/PDB/Raw/SymbolStream.cpp
===================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/SymbolStream.cpp
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/SymbolStream.cpp
@@ -0,0 +1,85 @@
+//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/StreamReader.h"
+
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+// Symbol stream is an array of symbol records. Each record starts with
+// length and type fields followed by type-specfic fields.
+namespace {
+struct SymbolHeader {
+  ulittle16_t Len; // Record length
+  ulittle16_t Type;
+};
+
+// For S_PUB32 symbol type.
+struct DataSym32 {
+  ulittle32_t TypIndex; // Type index, or Metadata token if a managed symbol
+  ulittle32_t off;
+  ulittle16_t seg;
+  char name[1];
+};
+
+// For S_PROCREF symbol type.
+struct RefSym {
+  ulittle32_t SumName;   // SUC of the name (?)
+  ulittle32_t SymOffset; // Offset of actual symbol in $$Symbols
+  ulittle16_t Mod;       // Module containing the actual symbol
+  char name[1];
+};
+}
+
+SymbolStream::SymbolStream(PDBFile &File, uint32_t StreamNum)
+    : Stream(StreamNum, File) {}
+
+SymbolStream::~SymbolStream() {}
+
+Error SymbolStream::reload() { return Error::success(); }
+
+static StringRef makeStringRef(char *p) { return {p, strlen(p)}; }
+
+Expected<std::string> SymbolStream::getSymbolName(uint32_t Off) const {
+  StreamReader Reader(Stream);
+  Reader.setOffset(Off);
+
+  // Read length field.
+  SymbolHeader Hdr;
+  if (Reader.readObject(&Hdr))
+    return make_error<RawError>(raw_error_code::corrupt_file,
+                                "Corrupted symbol stream.");
+
+  // Read the entire record.
+  std::vector<uint8_t> Buf(Hdr.Len - sizeof(Hdr.Type));
+  if (Reader.readBytes(Buf))
+    return make_error<RawError>(raw_error_code::corrupt_file,
+                                "Corrupted symbol stream.");
+
+  switch (Hdr.Type) {
+  case codeview::S_PUB32:
+    return makeStringRef(reinterpret_cast<DataSym32 *>(Buf.data())->name);
+  case codeview::S_PROCREF:
+    return makeStringRef(reinterpret_cast<RefSym *>(Buf.data())->name);
+  default:
+    return make_error<RawError>(raw_error_code::corrupt_file,
+                                "Unknown symbol type");
+  }
+  return Error::success();
+}
Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
===================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
@@ -317,6 +317,7 @@
 ; EMPTY-NEXT:   Address Map: [36, 0]
 ; EMPTY-NEXT:   Thunk Map: [4112]
 ; EMPTY-NEXT:   Section Offsets: [4096, 1]
+; EMPTY-NEXT:   Symbols: [?__purecall@@3PAXA, _main]
 ; EMPTY-NEXT: }
 
 ; BIG:      FileHeaders {
Index: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
===================================================================
--- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -415,6 +415,7 @@
   P.printList("Address Map", Publics.getAddressMap());
   P.printList("Thunk Map", Publics.getThunkMap());
   P.printList("Section Offsets", Publics.getSectionOffsets());
+  P.printList("Symbols", Publics.getSymbols());
   return Error::success();
 }