2013-04-04 02:31:38 +08:00
|
|
|
//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
|
|
|
/// \brief This file implements the COFF-specific dumper for llvm-readobj.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-06-13 01:38:55 +08:00
|
|
|
#include "ARMWinEHPrinter.h"
|
2016-01-14 03:32:35 +08:00
|
|
|
#include "CodeView.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "Error.h"
|
2014-01-13 16:04:33 +08:00
|
|
|
#include "ObjDumper.h"
|
2015-06-27 07:56:53 +08:00
|
|
|
#include "StackMapPrinter.h"
|
2014-05-26 04:26:45 +08:00
|
|
|
#include "Win64EHDumper.h"
|
2016-05-03 08:28:04 +08:00
|
|
|
#include "llvm-readobj.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
2014-11-20 01:10:39 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-01-11 08:35:43 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
2016-01-14 07:44:57 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
2016-01-15 03:20:17 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/Line.h"
|
2017-04-28 00:12:16 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
2017-05-03 00:56:09 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
2017-04-29 07:41:36 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
2016-05-24 07:41:13 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
2016-10-08 05:34:46 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
2016-05-24 07:41:13 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
2016-05-03 08:28:04 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
2016-01-14 07:44:57 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
2016-05-14 08:02:53 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
2016-11-09 06:24:53 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2017-03-03 04:52:51 +08:00
|
|
|
#include "llvm/Support/BinaryByteStream.h"
|
2017-04-29 07:41:36 +08:00
|
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
2014-01-13 16:04:33 +08:00
|
|
|
#include "llvm/Support/COFF.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
2013-12-19 19:37:14 +08:00
|
|
|
#include "llvm/Support/DataExtractor.h"
|
2017-04-29 07:41:36 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2017-02-17 07:35:45 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2016-05-03 08:28:04 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
#include "llvm/Support/Win64EH.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
2016-04-06 04:45:04 +08:00
|
|
|
#include <cstring>
|
2014-06-13 01:38:55 +08:00
|
|
|
#include <system_error>
|
2016-04-06 04:45:04 +08:00
|
|
|
#include <time.h>
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
2016-01-14 03:32:35 +08:00
|
|
|
using namespace llvm::codeview;
|
2016-01-14 07:44:57 +08:00
|
|
|
using namespace llvm::support;
|
2013-04-04 02:31:38 +08:00
|
|
|
using namespace llvm::Win64EH;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class COFFDumper : public ObjDumper {
|
|
|
|
public:
|
2016-05-24 07:41:13 +08:00
|
|
|
friend class COFFObjectDumpDelegate;
|
2016-05-03 08:28:04 +08:00
|
|
|
COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
: ObjDumper(Writer), Obj(Obj), Writer(Writer) {}
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-08-31 00:48:34 +08:00
|
|
|
void printFileHeaders() override;
|
|
|
|
void printSections() override;
|
|
|
|
void printRelocations() override;
|
|
|
|
void printSymbols() override;
|
|
|
|
void printDynamicSymbols() override;
|
|
|
|
void printUnwindInfo() override;
|
2014-10-03 01:02:18 +08:00
|
|
|
void printCOFFImports() override;
|
2015-01-04 05:35:09 +08:00
|
|
|
void printCOFFExports() override;
|
2014-10-08 03:37:52 +08:00
|
|
|
void printCOFFDirectives() override;
|
2014-11-19 08:18:07 +08:00
|
|
|
void printCOFFBaseReloc() override;
|
2016-06-03 01:10:43 +08:00
|
|
|
void printCOFFDebugDirectory() override;
|
2017-04-28 03:38:38 +08:00
|
|
|
void printCOFFResources() override;
|
2015-12-17 02:28:12 +08:00
|
|
|
void printCodeViewDebugInfo() override;
|
2017-03-25 01:26:38 +08:00
|
|
|
void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
|
|
|
|
llvm::codeview::TypeTableBuilder &CVTypes) override;
|
2015-06-27 07:56:53 +08:00
|
|
|
void printStackMap() const override;
|
2013-04-04 02:31:38 +08:00
|
|
|
private:
|
2014-03-18 14:53:02 +08:00
|
|
|
void printSymbol(const SymbolRef &Sym);
|
2016-01-15 01:51:57 +08:00
|
|
|
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc,
|
|
|
|
uint64_t Bias = 0);
|
2013-07-20 07:23:29 +08:00
|
|
|
void printDataDirectory(uint32_t Index, const std::string &FieldName);
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-11-05 14:24:35 +08:00
|
|
|
void printDOSHeader(const dos_header *DH);
|
2014-01-26 12:15:52 +08:00
|
|
|
template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
|
|
|
|
void printBaseOfDataField(const pe32_header *Hdr);
|
|
|
|
void printBaseOfDataField(const pe32plus_header *Hdr);
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
|
|
|
|
void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
|
|
|
|
StringRef getTypeName(TypeIndex Ty);
|
2016-01-15 08:11:21 +08:00
|
|
|
StringRef getFileNameForFileOffset(uint32_t FileOffset);
|
|
|
|
void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
|
2016-05-03 04:30:47 +08:00
|
|
|
void printTypeIndex(StringRef FieldName, TypeIndex TI) {
|
|
|
|
// Forward to CVTypeDumper for simplicity.
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
|
2016-05-03 04:30:47 +08:00
|
|
|
}
|
2013-12-19 19:37:14 +08:00
|
|
|
|
2014-10-24 06:25:31 +08:00
|
|
|
void printCodeViewSymbolsSubsection(StringRef Subsection,
|
|
|
|
const SectionRef &Section,
|
2016-01-15 01:51:54 +08:00
|
|
|
StringRef SectionContents);
|
2014-10-24 06:25:31 +08:00
|
|
|
|
2016-01-16 02:06:25 +08:00
|
|
|
void printCodeViewFileChecksums(StringRef Subsection);
|
|
|
|
|
2016-01-15 03:20:17 +08:00
|
|
|
void printCodeViewInlineeLines(StringRef Subsection);
|
|
|
|
|
2016-05-24 02:49:06 +08:00
|
|
|
void printRelocatedField(StringRef Label, const coff_section *Sec,
|
|
|
|
uint32_t RelocOffset, uint32_t Offset,
|
|
|
|
StringRef *RelocSym = nullptr);
|
|
|
|
|
2016-01-15 01:51:57 +08:00
|
|
|
void printBinaryBlockWithRelocs(StringRef Label, const SectionRef &Sec,
|
|
|
|
StringRef SectionContents, StringRef Block);
|
|
|
|
|
2016-01-15 08:11:21 +08:00
|
|
|
/// Given a .debug$S section, find the string table and file checksum table.
|
|
|
|
void initializeFileAndStringTables(StringRef Data);
|
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
void cacheRelocations();
|
|
|
|
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
|
|
|
|
SymbolRef &Sym);
|
|
|
|
std::error_code resolveSymbolName(const coff_section *Section,
|
|
|
|
uint64_t Offset, StringRef &Name);
|
2016-01-15 01:51:54 +08:00
|
|
|
std::error_code resolveSymbolName(const coff_section *Section,
|
|
|
|
StringRef SectionContents,
|
|
|
|
const void *RelocPtr, StringRef &Name);
|
2014-10-09 10:16:38 +08:00
|
|
|
void printImportedSymbols(iterator_range<imported_symbol_iterator> Range);
|
2014-11-13 11:22:54 +08:00
|
|
|
void printDelayImportedSymbols(
|
|
|
|
const DelayImportDirectoryEntryRef &I,
|
|
|
|
iterator_range<imported_symbol_iterator> Range);
|
2014-10-03 08:41:58 +08:00
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
|
|
|
|
|
|
|
|
const llvm::object::COFFObjectFile *Obj;
|
2015-07-06 22:26:07 +08:00
|
|
|
bool RelocCached = false;
|
2013-04-04 02:31:38 +08:00
|
|
|
RelocMapTy RelocMap;
|
2016-01-15 08:11:21 +08:00
|
|
|
StringRef CVFileChecksumTable;
|
2014-10-07 00:59:44 +08:00
|
|
|
StringRef CVStringTable;
|
2016-01-14 03:32:35 +08:00
|
|
|
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
ScopedPrinter &Writer;
|
|
|
|
TypeDatabase TypeDB;
|
2013-04-04 02:31:38 +08:00
|
|
|
};
|
|
|
|
|
2016-05-24 07:41:13 +08:00
|
|
|
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
|
|
|
|
public:
|
|
|
|
COFFObjectDumpDelegate(COFFDumper &CD, const SectionRef &SR,
|
|
|
|
const COFFObjectFile *Obj, StringRef SectionContents)
|
2016-05-24 11:32:34 +08:00
|
|
|
: CD(CD), SR(SR), SectionContents(SectionContents) {
|
2016-05-24 07:41:13 +08:00
|
|
|
Sec = Obj->getCOFFSection(SR);
|
|
|
|
}
|
|
|
|
|
2017-02-28 06:11:43 +08:00
|
|
|
uint32_t getRecordOffset(BinaryStreamReader Reader) override {
|
2016-10-21 02:31:19 +08:00
|
|
|
ArrayRef<uint8_t> Data;
|
|
|
|
if (auto EC = Reader.readLongestContiguousChunk(Data)) {
|
|
|
|
llvm::consumeError(std::move(EC));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return Data.data() - SectionContents.bytes_begin();
|
2016-05-24 07:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void printRelocatedField(StringRef Label, uint32_t RelocOffset,
|
|
|
|
uint32_t Offset, StringRef *RelocSym) override {
|
|
|
|
CD.printRelocatedField(Label, Sec, RelocOffset, Offset, RelocSym);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinaryBlockWithRelocs(StringRef Label,
|
|
|
|
ArrayRef<uint8_t> Block) override {
|
|
|
|
StringRef SBlock(reinterpret_cast<const char *>(Block.data()),
|
|
|
|
Block.size());
|
|
|
|
if (opts::CodeViewSubsectionBytes)
|
|
|
|
CD.printBinaryBlockWithRelocs(Label, SR, SectionContents, SBlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getFileNameForFileOffset(uint32_t FileOffset) override {
|
|
|
|
return CD.getFileNameForFileOffset(FileOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getStringTable() override { return CD.CVStringTable; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
COFFDumper &CD;
|
|
|
|
const SectionRef &SR;
|
|
|
|
const coff_section *Sec;
|
|
|
|
StringRef SectionContents;
|
|
|
|
};
|
|
|
|
|
2016-05-05 08:34:33 +08:00
|
|
|
} // end namespace
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code createCOFFDumper(const object::ObjectFile *Obj,
|
2016-05-03 08:28:04 +08:00
|
|
|
ScopedPrinter &Writer,
|
2014-06-13 11:07:50 +08:00
|
|
|
std::unique_ptr<ObjDumper> &Result) {
|
2013-04-04 02:31:38 +08:00
|
|
|
const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
|
|
|
|
if (!COFFObj)
|
|
|
|
return readobj_error::unsupported_obj_file_format;
|
|
|
|
|
|
|
|
Result.reset(new COFFDumper(COFFObj, Writer));
|
|
|
|
return readobj_error::success;
|
|
|
|
}
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
} // namespace llvm
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-05-26 04:26:37 +08:00
|
|
|
// Given a a section and an offset into this section the function returns the
|
|
|
|
// symbol used for the relocation at the offset.
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code COFFDumper::resolveSymbol(const coff_section *Section,
|
|
|
|
uint64_t Offset, SymbolRef &Sym) {
|
2015-07-06 22:26:07 +08:00
|
|
|
cacheRelocations();
|
2014-05-26 04:26:37 +08:00
|
|
|
const auto &Relocations = RelocMap[Section];
|
2016-05-29 14:18:08 +08:00
|
|
|
auto SymI = Obj->symbol_end();
|
2014-05-26 04:26:37 +08:00
|
|
|
for (const auto &Relocation : Relocations) {
|
2015-06-30 07:29:12 +08:00
|
|
|
uint64_t RelocationOffset = Relocation.getOffset();
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-05-26 04:26:37 +08:00
|
|
|
if (RelocationOffset == Offset) {
|
2016-05-29 14:18:08 +08:00
|
|
|
SymI = Relocation.getSymbol();
|
|
|
|
break;
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
}
|
2016-05-29 14:18:08 +08:00
|
|
|
if (SymI == Obj->symbol_end())
|
|
|
|
return readobj_error::unknown_symbol;
|
|
|
|
Sym = *SymI;
|
|
|
|
return readobj_error::success;
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2014-05-26 04:26:37 +08:00
|
|
|
// Given a section and an offset into this section the function returns the name
|
|
|
|
// of the symbol used for the relocation at the offset.
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code COFFDumper::resolveSymbolName(const coff_section *Section,
|
|
|
|
uint64_t Offset,
|
|
|
|
StringRef &Name) {
|
2014-05-26 04:26:37 +08:00
|
|
|
SymbolRef Symbol;
|
2014-06-13 11:07:50 +08:00
|
|
|
if (std::error_code EC = resolveSymbol(Section, Offset, Symbol))
|
2014-05-26 04:26:37 +08:00
|
|
|
return EC;
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> NameOrErr = Symbol.getName();
|
|
|
|
if (!NameOrErr)
|
|
|
|
return errorToErrorCode(NameOrErr.takeError());
|
2015-07-03 04:55:21 +08:00
|
|
|
Name = *NameOrErr;
|
2015-06-09 23:20:42 +08:00
|
|
|
return std::error_code();
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:54 +08:00
|
|
|
// Helper for when you have a pointer to real data and you want to know about
|
|
|
|
// relocations against it.
|
|
|
|
std::error_code COFFDumper::resolveSymbolName(const coff_section *Section,
|
|
|
|
StringRef SectionContents,
|
|
|
|
const void *RelocPtr,
|
|
|
|
StringRef &Name) {
|
|
|
|
assert(SectionContents.data() < RelocPtr &&
|
|
|
|
RelocPtr < SectionContents.data() + SectionContents.size() &&
|
|
|
|
"pointer to relocated object is not in section");
|
|
|
|
uint64_t Offset = ptrdiff_t(reinterpret_cast<const char *>(RelocPtr) -
|
|
|
|
SectionContents.data());
|
|
|
|
return resolveSymbolName(Section, Offset, Name);
|
|
|
|
}
|
|
|
|
|
2016-05-24 02:49:06 +08:00
|
|
|
void COFFDumper::printRelocatedField(StringRef Label, const coff_section *Sec,
|
|
|
|
uint32_t RelocOffset, uint32_t Offset,
|
|
|
|
StringRef *RelocSym) {
|
|
|
|
StringRef SymStorage;
|
|
|
|
StringRef &Symbol = RelocSym ? *RelocSym : SymStorage;
|
|
|
|
if (!resolveSymbolName(Sec, RelocOffset, Symbol))
|
|
|
|
W.printSymbolOffset(Label, Symbol, Offset);
|
|
|
|
else
|
|
|
|
W.printHex(Label, RelocOffset);
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:57 +08:00
|
|
|
void COFFDumper::printBinaryBlockWithRelocs(StringRef Label,
|
|
|
|
const SectionRef &Sec,
|
|
|
|
StringRef SectionContents,
|
|
|
|
StringRef Block) {
|
|
|
|
W.printBinaryBlock(Label, Block);
|
|
|
|
|
|
|
|
assert(SectionContents.begin() < Block.begin() &&
|
|
|
|
SectionContents.end() >= Block.end() &&
|
|
|
|
"Block is not contained in SectionContents");
|
|
|
|
uint64_t OffsetStart = Block.data() - SectionContents.data();
|
|
|
|
uint64_t OffsetEnd = OffsetStart + Block.size();
|
|
|
|
|
2016-05-24 07:41:13 +08:00
|
|
|
W.flush();
|
2016-01-15 01:51:57 +08:00
|
|
|
cacheRelocations();
|
|
|
|
ListScope D(W, "BlockRelocations");
|
|
|
|
const coff_section *Section = Obj->getCOFFSection(Sec);
|
|
|
|
const auto &Relocations = RelocMap[Section];
|
|
|
|
for (const auto &Relocation : Relocations) {
|
|
|
|
uint64_t RelocationOffset = Relocation.getOffset();
|
|
|
|
if (OffsetStart <= RelocationOffset && RelocationOffset < OffsetEnd)
|
|
|
|
printRelocation(Sec, Relocation, OffsetStart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
|
2014-03-11 11:08:37 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ),
|
2013-04-04 02:31:38 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI )
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
|
2013-06-13 03:10:33 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX ),
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
|
2014-01-27 12:22:24 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA ),
|
2013-06-13 03:10:33 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ),
|
2014-06-27 11:11:18 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER ),
|
2013-06-13 03:10:33 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ),
|
2014-06-27 11:11:18 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF ),
|
2013-06-13 03:10:33 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::SectionCharacteristics>
|
2013-04-04 02:31:38 +08:00
|
|
|
ImageSectionCharacteristics[] = {
|
2015-07-31 00:47:56 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD ),
|
2013-04-04 02:31:38 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE )
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
{ "Null" , COFF::IMAGE_SYM_TYPE_NULL },
|
|
|
|
{ "Void" , COFF::IMAGE_SYM_TYPE_VOID },
|
|
|
|
{ "Char" , COFF::IMAGE_SYM_TYPE_CHAR },
|
|
|
|
{ "Short" , COFF::IMAGE_SYM_TYPE_SHORT },
|
|
|
|
{ "Int" , COFF::IMAGE_SYM_TYPE_INT },
|
|
|
|
{ "Long" , COFF::IMAGE_SYM_TYPE_LONG },
|
|
|
|
{ "Float" , COFF::IMAGE_SYM_TYPE_FLOAT },
|
|
|
|
{ "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
|
|
|
|
{ "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
|
|
|
|
{ "Union" , COFF::IMAGE_SYM_TYPE_UNION },
|
|
|
|
{ "Enum" , COFF::IMAGE_SYM_TYPE_ENUM },
|
|
|
|
{ "MOE" , COFF::IMAGE_SYM_TYPE_MOE },
|
|
|
|
{ "Byte" , COFF::IMAGE_SYM_TYPE_BYTE },
|
|
|
|
{ "Word" , COFF::IMAGE_SYM_TYPE_WORD },
|
|
|
|
{ "UInt" , COFF::IMAGE_SYM_TYPE_UINT },
|
|
|
|
{ "DWord" , COFF::IMAGE_SYM_TYPE_DWORD }
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
{ "Null" , COFF::IMAGE_SYM_DTYPE_NULL },
|
|
|
|
{ "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER },
|
|
|
|
{ "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
|
|
|
|
{ "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY }
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
{ "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION },
|
|
|
|
{ "Null" , COFF::IMAGE_SYM_CLASS_NULL },
|
|
|
|
{ "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC },
|
|
|
|
{ "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL },
|
|
|
|
{ "Static" , COFF::IMAGE_SYM_CLASS_STATIC },
|
|
|
|
{ "Register" , COFF::IMAGE_SYM_CLASS_REGISTER },
|
|
|
|
{ "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF },
|
|
|
|
{ "Label" , COFF::IMAGE_SYM_CLASS_LABEL },
|
|
|
|
{ "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL },
|
|
|
|
{ "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
|
|
|
|
{ "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT },
|
|
|
|
{ "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG },
|
|
|
|
{ "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION },
|
|
|
|
{ "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG },
|
|
|
|
{ "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION },
|
|
|
|
{ "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
|
|
|
|
{ "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG },
|
|
|
|
{ "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM },
|
|
|
|
{ "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM },
|
|
|
|
{ "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD },
|
|
|
|
{ "Block" , COFF::IMAGE_SYM_CLASS_BLOCK },
|
|
|
|
{ "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION },
|
|
|
|
{ "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT },
|
|
|
|
{ "File" , COFF::IMAGE_SYM_CLASS_FILE },
|
|
|
|
{ "Section" , COFF::IMAGE_SYM_CLASS_SECTION },
|
|
|
|
{ "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL },
|
|
|
|
{ "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN }
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
|
2013-04-04 02:31:38 +08:00
|
|
|
{ "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
|
|
|
|
{ "Any" , COFF::IMAGE_COMDAT_SELECT_ANY },
|
|
|
|
{ "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE },
|
|
|
|
{ "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH },
|
|
|
|
{ "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE },
|
|
|
|
{ "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST },
|
|
|
|
{ "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
|
|
|
|
};
|
|
|
|
|
2016-06-03 01:10:43 +08:00
|
|
|
static const EnumEntry<COFF::DebugType> ImageDebugType[] = {
|
|
|
|
{ "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN },
|
|
|
|
{ "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF },
|
|
|
|
{ "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW },
|
|
|
|
{ "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO },
|
|
|
|
{ "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC },
|
|
|
|
{ "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION },
|
|
|
|
{ "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP },
|
|
|
|
{ "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC },
|
|
|
|
{ "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC },
|
|
|
|
{ "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND },
|
2016-06-03 01:32:11 +08:00
|
|
|
{ "Reserved10" , COFF::IMAGE_DEBUG_TYPE_RESERVED10 },
|
2016-06-03 01:10:43 +08:00
|
|
|
{ "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID },
|
|
|
|
{ "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE },
|
|
|
|
{ "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO },
|
|
|
|
{ "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG },
|
|
|
|
{ "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX },
|
2016-06-03 01:32:11 +08:00
|
|
|
{ "Repro" , COFF::IMAGE_DEBUG_TYPE_REPRO },
|
2016-06-03 01:10:43 +08:00
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<COFF::WeakExternalCharacteristics>
|
2013-04-04 02:31:38 +08:00
|
|
|
WeakExternalCharacteristics[] = {
|
|
|
|
{ "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
|
|
|
|
{ "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY },
|
|
|
|
{ "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<uint32_t> SubSectionTypes[] = {
|
2017-04-28 00:11:19 +08:00
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Symbols),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Lines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, StringTable),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FileChecksums),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FrameData),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, InlineeLines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeImports),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeExports),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, ILLines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FuncMDTokenMap),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, TypeMDTokenMap),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, MergedAssemblyInput),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CoffSymbolRVA),
|
2016-01-14 03:32:35 +08:00
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<uint32_t> FrameDataFlags[] = {
|
2016-01-14 03:32:35 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(FrameData, HasSEH),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(FrameData, HasEH),
|
|
|
|
LLVM_READOBJ_ENUM_ENT(FrameData, IsFunctionStart),
|
|
|
|
};
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static const EnumEntry<uint8_t> FileChecksumKindNames[] = {
|
2016-01-16 02:06:25 +08:00
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
|
|
|
|
};
|
|
|
|
|
2014-06-13 11:07:50 +08:00
|
|
|
template <typename T>
|
2016-04-06 04:45:04 +08:00
|
|
|
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
|
2014-09-10 20:51:52 +08:00
|
|
|
COFFSymbolRef Symbol,
|
|
|
|
uint8_t AuxSymbolIdx, const T *&Aux) {
|
2013-04-04 02:31:38 +08:00
|
|
|
ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
|
2014-09-10 20:51:52 +08:00
|
|
|
AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize());
|
2013-04-04 02:31:38 +08:00
|
|
|
Aux = reinterpret_cast<const T*>(AuxData.data());
|
|
|
|
return readobj_error::success;
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::cacheRelocations() {
|
2015-07-06 22:26:07 +08:00
|
|
|
if (RelocCached)
|
|
|
|
return;
|
|
|
|
RelocCached = true;
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
|
|
|
const coff_section *Section = Obj->getCOFFSection(S);
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const RelocationRef &Reloc : S.relocations())
|
2014-03-14 22:22:49 +08:00
|
|
|
RelocMap[Section].push_back(Reloc);
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
// Sort relocations by address.
|
|
|
|
std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
|
|
|
|
relocAddressLess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-20 07:23:29 +08:00
|
|
|
void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
|
|
|
|
const data_directory *Data;
|
|
|
|
if (Obj->getDataDirectory(Index, Data))
|
|
|
|
return;
|
|
|
|
W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
|
|
|
|
W.printHex(FieldName + "Size", Data->Size);
|
|
|
|
}
|
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
void COFFDumper::printFileHeaders() {
|
2014-09-10 20:51:52 +08:00
|
|
|
time_t TDS = Obj->getTimeDateStamp();
|
2013-04-04 02:31:38 +08:00
|
|
|
char FormattedTime[20] = { };
|
|
|
|
strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
|
|
|
|
|
|
|
|
{
|
|
|
|
DictScope D(W, "ImageFileHeader");
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printEnum ("Machine", Obj->getMachine(),
|
2013-04-04 02:31:38 +08:00
|
|
|
makeArrayRef(ImageFileMachineType));
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printNumber("SectionCount", Obj->getNumberOfSections());
|
|
|
|
W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
|
|
|
|
W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
|
|
|
|
W.printNumber("SymbolCount", Obj->getNumberOfSymbols());
|
|
|
|
W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
|
|
|
|
W.printFlags ("Characteristics", Obj->getCharacteristics(),
|
2013-04-04 02:31:38 +08:00
|
|
|
makeArrayRef(ImageFileCharacteristics));
|
|
|
|
}
|
2013-06-13 03:10:33 +08:00
|
|
|
|
|
|
|
// Print PE header. This header does not exist if this is an object file and
|
|
|
|
// not an executable.
|
2014-04-25 12:24:47 +08:00
|
|
|
const pe32_header *PEHeader = nullptr;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Obj->getPE32Header(PEHeader));
|
2014-01-26 12:15:52 +08:00
|
|
|
if (PEHeader)
|
|
|
|
printPEHeader<pe32_header>(PEHeader);
|
|
|
|
|
2014-04-25 12:24:47 +08:00
|
|
|
const pe32plus_header *PEPlusHeader = nullptr;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Obj->getPE32PlusHeader(PEPlusHeader));
|
2014-01-26 12:15:52 +08:00
|
|
|
if (PEPlusHeader)
|
|
|
|
printPEHeader<pe32plus_header>(PEPlusHeader);
|
2014-11-05 14:24:35 +08:00
|
|
|
|
|
|
|
if (const dos_header *DH = Obj->getDOSHeader())
|
|
|
|
printDOSHeader(DH);
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printDOSHeader(const dos_header *DH) {
|
|
|
|
DictScope D(W, "DOSHeader");
|
|
|
|
W.printString("Magic", StringRef(DH->Magic, sizeof(DH->Magic)));
|
|
|
|
W.printNumber("UsedBytesInTheLastPage", DH->UsedBytesInTheLastPage);
|
|
|
|
W.printNumber("FileSizeInPages", DH->FileSizeInPages);
|
|
|
|
W.printNumber("NumberOfRelocationItems", DH->NumberOfRelocationItems);
|
|
|
|
W.printNumber("HeaderSizeInParagraphs", DH->HeaderSizeInParagraphs);
|
|
|
|
W.printNumber("MinimumExtraParagraphs", DH->MinimumExtraParagraphs);
|
|
|
|
W.printNumber("MaximumExtraParagraphs", DH->MaximumExtraParagraphs);
|
|
|
|
W.printNumber("InitialRelativeSS", DH->InitialRelativeSS);
|
|
|
|
W.printNumber("InitialSP", DH->InitialSP);
|
|
|
|
W.printNumber("Checksum", DH->Checksum);
|
|
|
|
W.printNumber("InitialIP", DH->InitialIP);
|
|
|
|
W.printNumber("InitialRelativeCS", DH->InitialRelativeCS);
|
|
|
|
W.printNumber("AddressOfRelocationTable", DH->AddressOfRelocationTable);
|
|
|
|
W.printNumber("OverlayNumber", DH->OverlayNumber);
|
|
|
|
W.printNumber("OEMid", DH->OEMid);
|
|
|
|
W.printNumber("OEMinfo", DH->OEMinfo);
|
|
|
|
W.printNumber("AddressOfNewExeHeader", DH->AddressOfNewExeHeader);
|
2014-01-26 12:15:52 +08:00
|
|
|
}
|
2013-06-13 03:10:33 +08:00
|
|
|
|
2014-01-26 12:15:52 +08:00
|
|
|
template <class PEHeader>
|
|
|
|
void COFFDumper::printPEHeader(const PEHeader *Hdr) {
|
|
|
|
DictScope D(W, "ImageOptionalHeader");
|
|
|
|
W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
|
|
|
|
W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
|
|
|
|
W.printNumber("SizeOfCode", Hdr->SizeOfCode);
|
|
|
|
W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData);
|
|
|
|
W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData);
|
|
|
|
W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint);
|
|
|
|
W.printHex ("BaseOfCode", Hdr->BaseOfCode);
|
|
|
|
printBaseOfDataField(Hdr);
|
|
|
|
W.printHex ("ImageBase", Hdr->ImageBase);
|
|
|
|
W.printNumber("SectionAlignment", Hdr->SectionAlignment);
|
|
|
|
W.printNumber("FileAlignment", Hdr->FileAlignment);
|
|
|
|
W.printNumber("MajorOperatingSystemVersion",
|
|
|
|
Hdr->MajorOperatingSystemVersion);
|
|
|
|
W.printNumber("MinorOperatingSystemVersion",
|
|
|
|
Hdr->MinorOperatingSystemVersion);
|
|
|
|
W.printNumber("MajorImageVersion", Hdr->MajorImageVersion);
|
|
|
|
W.printNumber("MinorImageVersion", Hdr->MinorImageVersion);
|
|
|
|
W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion);
|
|
|
|
W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
|
|
|
|
W.printNumber("SizeOfImage", Hdr->SizeOfImage);
|
|
|
|
W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
|
|
|
|
W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
|
2014-11-18 10:45:28 +08:00
|
|
|
W.printFlags ("Characteristics", Hdr->DLLCharacteristics,
|
2014-01-26 12:15:52 +08:00
|
|
|
makeArrayRef(PEDLLCharacteristics));
|
|
|
|
W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
|
|
|
|
W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
|
|
|
|
W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
|
|
|
|
W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit);
|
|
|
|
W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize);
|
|
|
|
|
|
|
|
if (Hdr->NumberOfRvaAndSize > 0) {
|
|
|
|
DictScope D(W, "DataDirectory");
|
|
|
|
static const char * const directory[] = {
|
|
|
|
"ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
|
|
|
|
"CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
|
|
|
|
"GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
|
|
|
|
"DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
|
|
|
|
};
|
|
|
|
|
2016-06-03 01:10:43 +08:00
|
|
|
for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i)
|
2014-01-26 12:15:52 +08:00
|
|
|
printDataDirectory(i, directory[i]);
|
2016-06-03 01:10:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printCOFFDebugDirectory() {
|
|
|
|
ListScope LS(W, "DebugDirectory");
|
|
|
|
for (const debug_directory &D : Obj->debug_directories()) {
|
|
|
|
char FormattedTime[20] = {};
|
|
|
|
time_t TDS = D.TimeDateStamp;
|
|
|
|
strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
|
|
|
|
DictScope S(W, "DebugEntry");
|
|
|
|
W.printHex("Characteristics", D.Characteristics);
|
|
|
|
W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp);
|
|
|
|
W.printHex("MajorVersion", D.MajorVersion);
|
|
|
|
W.printHex("MinorVersion", D.MinorVersion);
|
|
|
|
W.printEnum("Type", D.Type, makeArrayRef(ImageDebugType));
|
|
|
|
W.printHex("SizeOfData", D.SizeOfData);
|
|
|
|
W.printHex("AddressOfRawData", D.AddressOfRawData);
|
|
|
|
W.printHex("PointerToRawData", D.PointerToRawData);
|
|
|
|
if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) {
|
2016-08-09 08:25:12 +08:00
|
|
|
const codeview::DebugInfo *DebugInfo;
|
2016-06-03 01:10:43 +08:00
|
|
|
StringRef PDBFileName;
|
2016-08-09 08:25:12 +08:00
|
|
|
error(Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName));
|
2016-06-03 01:10:43 +08:00
|
|
|
DictScope PDBScope(W, "PDBInfo");
|
2016-08-09 08:25:12 +08:00
|
|
|
W.printHex("PDBSignature", DebugInfo->Signature.CVSignature);
|
|
|
|
if (DebugInfo->Signature.CVSignature == OMF::Signature::PDB70) {
|
|
|
|
W.printBinary("PDBGUID", makeArrayRef(DebugInfo->PDB70.Signature));
|
|
|
|
W.printNumber("PDBAge", DebugInfo->PDB70.Age);
|
|
|
|
W.printString("PDBFileName", PDBFileName);
|
|
|
|
}
|
2016-06-03 01:10:43 +08:00
|
|
|
} else {
|
|
|
|
// FIXME: Type values of 12 and 13 are commonly observed but are not in
|
|
|
|
// the documented type enum. Figure out what they mean.
|
|
|
|
ArrayRef<uint8_t> RawData;
|
|
|
|
error(
|
|
|
|
Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData));
|
|
|
|
W.printBinaryBlock("RawData", RawData);
|
2013-07-20 07:23:29 +08:00
|
|
|
}
|
2013-06-13 03:10:33 +08:00
|
|
|
}
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2014-01-26 12:15:52 +08:00
|
|
|
void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
|
|
|
|
W.printHex("BaseOfData", Hdr->BaseOfData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}
|
|
|
|
|
2015-12-17 02:28:12 +08:00
|
|
|
void COFFDumper::printCodeViewDebugInfo() {
|
2016-01-14 03:32:35 +08:00
|
|
|
// Print types first to build CVUDTNames, then print symbols.
|
2015-12-17 02:28:12 +08:00
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef SectionName;
|
|
|
|
error(S.getName(SectionName));
|
|
|
|
if (SectionName == ".debug$T")
|
|
|
|
printCodeViewTypeSection(SectionName, S);
|
|
|
|
}
|
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
|
|
|
StringRef SectionName;
|
|
|
|
error(S.getName(SectionName));
|
|
|
|
if (SectionName == ".debug$S")
|
|
|
|
printCodeViewSymbolSection(SectionName, S);
|
2015-12-17 02:28:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 08:11:21 +08:00
|
|
|
void COFFDumper::initializeFileAndStringTables(StringRef Data) {
|
|
|
|
while (!Data.empty() && (CVFileChecksumTable.data() == nullptr ||
|
|
|
|
CVStringTable.data() == nullptr)) {
|
|
|
|
// The section consists of a number of subsection in the following format:
|
|
|
|
// |SubSectionType|SubSectionSize|Contents...|
|
|
|
|
uint32_t SubType, SubSectionSize;
|
2016-05-13 01:45:44 +08:00
|
|
|
error(consume(Data, SubType));
|
|
|
|
error(consume(Data, SubSectionSize));
|
2016-01-15 08:11:21 +08:00
|
|
|
if (SubSectionSize > Data.size())
|
|
|
|
return error(object_error::parse_failed);
|
2017-04-28 00:11:19 +08:00
|
|
|
switch (ModuleDebugFragmentKind(SubType)) {
|
|
|
|
case ModuleDebugFragmentKind::FileChecksums:
|
2016-01-15 08:11:21 +08:00
|
|
|
CVFileChecksumTable = Data.substr(0, SubSectionSize);
|
|
|
|
break;
|
2017-04-28 00:11:19 +08:00
|
|
|
case ModuleDebugFragmentKind::StringTable:
|
2016-01-15 08:11:21 +08:00
|
|
|
CVStringTable = Data.substr(0, SubSectionSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-29 04:04:48 +08:00
|
|
|
uint32_t PaddedSize = alignTo(SubSectionSize, 4);
|
|
|
|
if (PaddedSize > Data.size())
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
Data = Data.drop_front(PaddedSize);
|
2016-01-15 08:11:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
|
|
|
const SectionRef &Section) {
|
|
|
|
StringRef SectionContents;
|
|
|
|
error(Section.getContents(SectionContents));
|
|
|
|
StringRef Data = SectionContents;
|
2013-12-19 19:37:14 +08:00
|
|
|
|
|
|
|
SmallVector<StringRef, 10> FunctionNames;
|
|
|
|
StringMap<StringRef> FunctionLineTables;
|
|
|
|
|
2015-02-19 03:32:05 +08:00
|
|
|
ListScope D(W, "CodeViewDebugInfo");
|
2016-01-14 03:32:35 +08:00
|
|
|
// Print the section to allow correlation with printSections.
|
|
|
|
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
|
|
|
|
|
|
|
|
uint32_t Magic;
|
2016-05-13 01:45:44 +08:00
|
|
|
error(consume(Data, Magic));
|
2016-01-14 03:32:35 +08:00
|
|
|
W.printHex("Magic", Magic);
|
|
|
|
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
|
|
|
return error(object_error::parse_failed);
|
|
|
|
|
2016-01-15 08:11:21 +08:00
|
|
|
initializeFileAndStringTables(Data);
|
|
|
|
|
2016-06-03 11:25:59 +08:00
|
|
|
// TODO: Convert this over to using ModuleSubstreamVisitor.
|
2016-01-14 03:32:35 +08:00
|
|
|
while (!Data.empty()) {
|
|
|
|
// The section consists of a number of subsection in the following format:
|
|
|
|
// |SubSectionType|SubSectionSize|Contents...|
|
|
|
|
uint32_t SubType, SubSectionSize;
|
2016-05-13 01:45:44 +08:00
|
|
|
error(consume(Data, SubType));
|
|
|
|
error(consume(Data, SubSectionSize));
|
2016-01-14 03:32:35 +08:00
|
|
|
|
|
|
|
ListScope S(W, "Subsection");
|
|
|
|
W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
|
|
|
|
W.printHex("SubSectionSize", SubSectionSize);
|
|
|
|
|
|
|
|
// Get the contents of the subsection.
|
|
|
|
if (SubSectionSize > Data.size())
|
|
|
|
return error(object_error::parse_failed);
|
|
|
|
StringRef Contents = Data.substr(0, SubSectionSize);
|
|
|
|
|
|
|
|
// Add SubSectionSize to the current offset and align that offset to find
|
|
|
|
// the next subsection.
|
|
|
|
size_t SectionOffset = Data.data() - SectionContents.data();
|
|
|
|
size_t NextOffset = SectionOffset + SubSectionSize;
|
2016-01-15 05:06:47 +08:00
|
|
|
NextOffset = alignTo(NextOffset, 4);
|
2016-05-29 04:04:50 +08:00
|
|
|
if (NextOffset > SectionContents.size())
|
|
|
|
return error(object_error::parse_failed);
|
2016-01-14 03:32:35 +08:00
|
|
|
Data = SectionContents.drop_front(NextOffset);
|
|
|
|
|
|
|
|
// Optionally print the subsection bytes in case our parsing gets confused
|
|
|
|
// later.
|
|
|
|
if (opts::CodeViewSubsectionBytes)
|
2016-01-16 06:09:13 +08:00
|
|
|
printBinaryBlockWithRelocs("SubSectionContents", Section, SectionContents,
|
|
|
|
Contents);
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2017-04-28 00:11:19 +08:00
|
|
|
switch (ModuleDebugFragmentKind(SubType)) {
|
|
|
|
case ModuleDebugFragmentKind::Symbols:
|
2016-01-15 01:51:54 +08:00
|
|
|
printCodeViewSymbolsSubsection(Contents, Section, SectionContents);
|
2016-01-14 03:32:35 +08:00
|
|
|
break;
|
2016-01-15 03:20:17 +08:00
|
|
|
|
2017-04-28 00:11:19 +08:00
|
|
|
case ModuleDebugFragmentKind::InlineeLines:
|
2016-01-15 03:20:17 +08:00
|
|
|
printCodeViewInlineeLines(Contents);
|
|
|
|
break;
|
|
|
|
|
2017-04-28 00:11:19 +08:00
|
|
|
case ModuleDebugFragmentKind::FileChecksums:
|
2016-01-16 02:06:25 +08:00
|
|
|
printCodeViewFileChecksums(Contents);
|
|
|
|
break;
|
|
|
|
|
2017-04-28 00:11:19 +08:00
|
|
|
case ModuleDebugFragmentKind::Lines: {
|
2016-01-14 03:32:35 +08:00
|
|
|
// Holds a PC to file:line table. Some data to parse this subsection is
|
|
|
|
// stored in the other subsections, so just check sanity and store the
|
|
|
|
// pointers for deferred processing.
|
|
|
|
|
|
|
|
if (SubSectionSize < 12) {
|
|
|
|
// There should be at least three words to store two function
|
|
|
|
// relocations and size of the code.
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-19 19:37:14 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef LinkageName;
|
|
|
|
error(resolveSymbolName(Obj->getCOFFSection(Section), SectionOffset,
|
|
|
|
LinkageName));
|
|
|
|
W.printString("LinkageName", LinkageName);
|
|
|
|
if (FunctionLineTables.count(LinkageName) != 0) {
|
|
|
|
// Saw debug info for this function already?
|
2013-12-19 19:37:14 +08:00
|
|
|
error(object_error::parse_failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
FunctionLineTables[LinkageName] = Contents;
|
|
|
|
FunctionNames.push_back(LinkageName);
|
|
|
|
break;
|
|
|
|
}
|
2017-04-28 00:11:19 +08:00
|
|
|
case ModuleDebugFragmentKind::FrameData: {
|
2016-01-16 06:09:13 +08:00
|
|
|
// First four bytes is a relocation against the function.
|
2017-02-28 08:04:07 +08:00
|
|
|
BinaryByteStream S(Contents, llvm::support::little);
|
2017-02-28 06:11:43 +08:00
|
|
|
BinaryStreamReader SR(S);
|
2017-02-26 01:04:23 +08:00
|
|
|
const uint32_t *CodePtr;
|
|
|
|
error(SR.readObject(CodePtr));
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef LinkageName;
|
2016-01-16 06:09:13 +08:00
|
|
|
error(resolveSymbolName(Obj->getCOFFSection(Section), SectionContents,
|
2017-02-26 01:04:23 +08:00
|
|
|
CodePtr, LinkageName));
|
2016-01-16 06:09:13 +08:00
|
|
|
W.printString("LinkageName", LinkageName);
|
|
|
|
|
|
|
|
// To find the active frame description, search this array for the
|
|
|
|
// smallest PC range that includes the current PC.
|
2016-10-21 02:31:19 +08:00
|
|
|
while (!SR.empty()) {
|
2016-01-16 06:09:13 +08:00
|
|
|
const FrameData *FD;
|
2016-10-21 02:31:19 +08:00
|
|
|
error(SR.readObject(FD));
|
2016-05-29 03:45:49 +08:00
|
|
|
|
|
|
|
if (FD->FrameFunc >= CVStringTable.size())
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
|
|
|
|
StringRef FrameFunc =
|
|
|
|
CVStringTable.drop_front(FD->FrameFunc).split('\0').first;
|
|
|
|
|
2016-01-16 06:09:13 +08:00
|
|
|
DictScope S(W, "FrameData");
|
|
|
|
W.printHex("RvaStart", FD->RvaStart);
|
|
|
|
W.printHex("CodeSize", FD->CodeSize);
|
|
|
|
W.printHex("LocalSize", FD->LocalSize);
|
|
|
|
W.printHex("ParamsSize", FD->ParamsSize);
|
|
|
|
W.printHex("MaxStackSize", FD->MaxStackSize);
|
2016-05-29 03:45:49 +08:00
|
|
|
W.printString("FrameFunc", FrameFunc);
|
2016-01-16 06:09:13 +08:00
|
|
|
W.printHex("PrologSize", FD->PrologSize);
|
|
|
|
W.printHex("SavedRegsSize", FD->SavedRegsSize);
|
|
|
|
W.printFlags("Flags", FD->Flags, makeArrayRef(FrameDataFlags));
|
2013-12-19 19:37:14 +08:00
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-12-19 19:37:14 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
// Do nothing for unrecognized subsections.
|
|
|
|
default:
|
|
|
|
break;
|
2013-12-19 19:37:14 +08:00
|
|
|
}
|
2016-01-16 06:09:13 +08:00
|
|
|
W.flush();
|
2013-12-19 19:37:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dump the line tables now that we've read all the subsections and know all
|
|
|
|
// the required information.
|
|
|
|
for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) {
|
|
|
|
StringRef Name = FunctionNames[I];
|
|
|
|
ListScope S(W, "FunctionLineTable");
|
2015-12-15 09:23:55 +08:00
|
|
|
W.printString("LinkageName", Name);
|
2013-12-19 19:37:14 +08:00
|
|
|
|
2017-04-29 07:41:36 +08:00
|
|
|
BinaryByteStream LineTableInfo(FunctionLineTables[Name], support::little);
|
|
|
|
BinaryStreamReader Reader(LineTableInfo);
|
|
|
|
|
2017-05-02 00:46:39 +08:00
|
|
|
ModuleDebugLineFragmentRef LineInfo;
|
2017-04-29 07:41:36 +08:00
|
|
|
error(LineInfo.initialize(Reader));
|
|
|
|
|
|
|
|
W.printHex("Flags", LineInfo.header()->Flags);
|
|
|
|
W.printHex("CodeSize", LineInfo.header()->CodeSize);
|
|
|
|
for (const auto &Entry : LineInfo) {
|
2015-07-09 12:27:36 +08:00
|
|
|
|
2013-12-19 19:37:14 +08:00
|
|
|
ListScope S(W, "FilenameSegment");
|
2017-04-29 07:41:36 +08:00
|
|
|
printFileNameForOffset("Filename", Entry.NameIndex);
|
2017-04-29 08:03:32 +08:00
|
|
|
uint32_t ColumnIndex = 0;
|
2017-04-29 07:41:36 +08:00
|
|
|
for (const auto &Line : Entry.LineNumbers) {
|
|
|
|
if (Line.Offset >= LineInfo.header()->CodeSize) {
|
2013-12-19 19:37:14 +08:00
|
|
|
error(object_error::parse_failed);
|
|
|
|
return;
|
|
|
|
}
|
2017-04-29 07:41:36 +08:00
|
|
|
|
|
|
|
std::string PC = formatv("+{0:X}", uint32_t(Line.Offset));
|
|
|
|
ListScope PCScope(W, PC);
|
|
|
|
codeview::LineInfo LI(Line.Flags);
|
|
|
|
|
2016-02-05 01:57:12 +08:00
|
|
|
if (LI.isAlwaysStepInto())
|
|
|
|
W.printString("StepInto", StringRef("Always"));
|
|
|
|
else if (LI.isNeverStepInto())
|
|
|
|
W.printString("StepInto", StringRef("Never"));
|
|
|
|
else
|
|
|
|
W.printNumber("LineNumberStart", LI.getStartLine());
|
|
|
|
W.printNumber("LineNumberEndDelta", LI.getLineDelta());
|
|
|
|
W.printBoolean("IsStatement", LI.isStatement());
|
2017-04-29 09:13:21 +08:00
|
|
|
if (LineInfo.hasColumnInfo()) {
|
2017-04-29 08:03:32 +08:00
|
|
|
W.printNumber("ColStart", Entry.Columns[ColumnIndex].StartColumn);
|
|
|
|
W.printNumber("ColEnd", Entry.Columns[ColumnIndex].EndColumn);
|
|
|
|
++ColumnIndex;
|
2016-01-13 09:05:16 +08:00
|
|
|
}
|
|
|
|
}
|
2013-12-19 19:37:14 +08:00
|
|
|
}
|
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
}
|
|
|
|
|
2014-10-24 06:25:31 +08:00
|
|
|
void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
|
|
|
|
const SectionRef &Section,
|
2016-01-15 01:51:54 +08:00
|
|
|
StringRef SectionContents) {
|
2016-05-24 07:41:13 +08:00
|
|
|
ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(),
|
|
|
|
Subsection.bytes_end());
|
|
|
|
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
|
|
|
SectionContents);
|
2016-01-14 03:32:35 +08:00
|
|
|
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
|
|
|
|
opts::CodeViewSubsectionBytes);
|
2017-02-28 08:04:07 +08:00
|
|
|
BinaryByteStream Stream(BinaryData, llvm::support::little);
|
2016-05-28 13:21:57 +08:00
|
|
|
CVSymbolArray Symbols;
|
2017-02-28 06:11:43 +08:00
|
|
|
BinaryStreamReader Reader(Stream);
|
2016-05-28 13:21:57 +08:00
|
|
|
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
|
|
|
|
consumeError(std::move(EC));
|
|
|
|
W.flush();
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2016-10-08 05:34:46 +08:00
|
|
|
if (auto EC = CVSD.dump(Symbols)) {
|
2016-01-16 06:09:13 +08:00
|
|
|
W.flush();
|
2016-10-08 05:34:46 +08:00
|
|
|
error(std::move(EC));
|
2016-01-14 03:32:35 +08:00
|
|
|
}
|
2016-01-16 06:09:13 +08:00
|
|
|
W.flush();
|
2016-01-14 03:32:35 +08:00
|
|
|
}
|
|
|
|
|
2016-01-16 02:06:25 +08:00
|
|
|
void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
|
2017-02-28 08:04:07 +08:00
|
|
|
BinaryByteStream S(Subsection, llvm::support::little);
|
2017-02-28 06:11:43 +08:00
|
|
|
BinaryStreamReader SR(S);
|
2017-05-02 00:46:39 +08:00
|
|
|
ModuleDebugFileChecksumFragmentRef Checksums;
|
2017-04-28 00:12:16 +08:00
|
|
|
error(Checksums.initialize(SR));
|
|
|
|
|
|
|
|
for (auto &FC : Checksums) {
|
2016-01-16 02:06:25 +08:00
|
|
|
DictScope S(W, "FileChecksum");
|
2017-04-28 00:12:16 +08:00
|
|
|
|
|
|
|
if (FC.FileNameOffset >= CVStringTable.size())
|
2016-01-16 02:06:25 +08:00
|
|
|
error(object_error::parse_failed);
|
|
|
|
StringRef Filename =
|
2017-04-28 00:12:16 +08:00
|
|
|
CVStringTable.drop_front(FC.FileNameOffset).split('\0').first;
|
|
|
|
W.printHex("Filename", Filename, FC.FileNameOffset);
|
|
|
|
W.printHex("ChecksumSize", FC.Checksum.size());
|
|
|
|
W.printEnum("ChecksumKind", uint8_t(FC.Kind),
|
2016-01-16 02:06:25 +08:00
|
|
|
makeArrayRef(FileChecksumKindNames));
|
2017-04-28 00:12:16 +08:00
|
|
|
|
|
|
|
W.printBinary("ChecksumBytes", FC.Checksum);
|
2016-01-16 02:06:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 03:20:17 +08:00
|
|
|
void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
|
2017-02-28 08:04:07 +08:00
|
|
|
BinaryByteStream S(Subsection, llvm::support::little);
|
2017-02-28 06:11:43 +08:00
|
|
|
BinaryStreamReader SR(S);
|
2017-05-03 00:56:09 +08:00
|
|
|
ModuleDebugInlineeLineFragmentRef Lines;
|
|
|
|
error(Lines.initialize(SR));
|
2016-01-15 03:20:17 +08:00
|
|
|
|
2017-05-03 00:56:09 +08:00
|
|
|
for (auto &Line : Lines) {
|
2016-01-15 03:20:17 +08:00
|
|
|
DictScope S(W, "InlineeSourceLine");
|
2017-05-03 00:56:09 +08:00
|
|
|
printTypeIndex("Inlinee", Line.Header->Inlinee);
|
|
|
|
printFileNameForOffset("FileID", Line.Header->FileID);
|
|
|
|
W.printNumber("SourceLineNum", Line.Header->SourceLineNum);
|
|
|
|
|
|
|
|
if (Lines.hasExtraFiles()) {
|
|
|
|
W.printNumber("ExtraFileCount", Line.ExtraFiles.size());
|
2016-01-15 03:20:17 +08:00
|
|
|
ListScope ExtraFiles(W, "ExtraFiles");
|
2017-05-03 00:56:09 +08:00
|
|
|
for (const auto &FID : Line.ExtraFiles) {
|
|
|
|
printFileNameForOffset("FileID", FID);
|
2016-01-15 03:20:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 08:11:21 +08:00
|
|
|
StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
|
|
|
|
// The file checksum subsection should precede all references to it.
|
|
|
|
if (!CVFileChecksumTable.data() || !CVStringTable.data())
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
// Check if the file checksum table offset is valid.
|
|
|
|
if (FileOffset >= CVFileChecksumTable.size())
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
|
|
|
|
// The string table offset comes first before the file checksum.
|
|
|
|
StringRef Data = CVFileChecksumTable.drop_front(FileOffset);
|
|
|
|
uint32_t StringOffset;
|
2016-05-13 01:45:44 +08:00
|
|
|
error(consume(Data, StringOffset));
|
2016-01-15 08:11:21 +08:00
|
|
|
|
|
|
|
// Check if the string table offset is valid.
|
|
|
|
if (StringOffset >= CVStringTable.size())
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
|
|
|
|
// Return the null-terminated string.
|
|
|
|
return CVStringTable.drop_front(StringOffset).split('\0').first;
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
|
|
|
|
W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
|
|
|
|
}
|
|
|
|
|
2017-03-25 01:26:38 +08:00
|
|
|
void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs,
|
|
|
|
TypeTableBuilder &CVTypes) {
|
2016-05-14 08:02:53 +08:00
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
|
|
|
StringRef SectionName;
|
|
|
|
error(S.getName(SectionName));
|
|
|
|
if (SectionName == ".debug$T") {
|
|
|
|
StringRef Data;
|
|
|
|
error(S.getContents(Data));
|
2016-05-29 03:17:48 +08:00
|
|
|
uint32_t Magic;
|
|
|
|
error(consume(Data, Magic));
|
2016-05-14 08:02:53 +08:00
|
|
|
if (Magic != 4)
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Data.data()),
|
|
|
|
Data.size());
|
2017-02-28 08:04:07 +08:00
|
|
|
BinaryByteStream Stream(Bytes, llvm::support::little);
|
2016-05-28 13:21:57 +08:00
|
|
|
CVTypeArray Types;
|
2017-02-28 06:11:43 +08:00
|
|
|
BinaryStreamReader Reader(Stream);
|
2016-05-28 13:21:57 +08:00
|
|
|
if (auto EC = Reader.readArray(Types, Reader.getLength())) {
|
|
|
|
consumeError(std::move(EC));
|
|
|
|
W.flush();
|
|
|
|
error(object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
2017-04-04 07:58:15 +08:00
|
|
|
if (auto EC = mergeTypeStreams(CVIDs, CVTypes, nullptr, Types))
|
|
|
|
return error(std::move(EC));
|
2016-05-14 08:02:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
|
|
|
|
const SectionRef &Section) {
|
|
|
|
ListScope D(W, "CodeViewTypes");
|
|
|
|
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
|
2016-05-03 07:45:03 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef Data;
|
|
|
|
error(Section.getContents(Data));
|
2016-05-03 02:10:00 +08:00
|
|
|
if (opts::CodeViewSubsectionBytes)
|
|
|
|
W.printBinaryBlock("Data", Data);
|
2016-05-03 04:30:47 +08:00
|
|
|
|
2016-05-04 06:18:17 +08:00
|
|
|
uint32_t Magic;
|
2016-05-13 01:45:44 +08:00
|
|
|
error(consume(Data, Magic));
|
2016-05-05 03:39:28 +08:00
|
|
|
W.printHex("Magic", Magic);
|
2016-05-04 06:18:17 +08:00
|
|
|
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
2016-05-05 03:39:28 +08:00
|
|
|
return error(object_error::parse_failed);
|
2016-01-14 03:32:35 +08:00
|
|
|
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
CVTypeDumper CVTD(TypeDB);
|
|
|
|
TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
|
|
|
|
if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
|
2016-05-05 08:34:33 +08:00
|
|
|
W.flush();
|
2016-06-17 02:22:27 +08:00
|
|
|
error(llvm::errorToErrorCode(std::move(EC)));
|
2016-05-05 03:39:28 +08:00
|
|
|
}
|
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
void COFFDumper::printSections() {
|
|
|
|
ListScope SectionsD(W, "Sections");
|
|
|
|
int SectionNumber = 0;
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const SectionRef &Sec : Obj->sections()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
++SectionNumber;
|
2014-03-18 14:53:02 +08:00
|
|
|
const coff_section *Section = Obj->getCOFFSection(Sec);
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
StringRef Name;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Sec.getName(Name));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
DictScope D(W, "Section");
|
|
|
|
W.printNumber("Number", SectionNumber);
|
|
|
|
W.printBinary("Name", Name, Section->Name);
|
|
|
|
W.printHex ("VirtualSize", Section->VirtualSize);
|
|
|
|
W.printHex ("VirtualAddress", Section->VirtualAddress);
|
|
|
|
W.printNumber("RawDataSize", Section->SizeOfRawData);
|
|
|
|
W.printHex ("PointerToRawData", Section->PointerToRawData);
|
|
|
|
W.printHex ("PointerToRelocations", Section->PointerToRelocations);
|
|
|
|
W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers);
|
|
|
|
W.printNumber("RelocationCount", Section->NumberOfRelocations);
|
|
|
|
W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
|
|
|
|
W.printFlags ("Characteristics", Section->Characteristics,
|
|
|
|
makeArrayRef(ImageSectionCharacteristics),
|
|
|
|
COFF::SectionCharacteristics(0x00F00000));
|
|
|
|
|
|
|
|
if (opts::SectionRelocations) {
|
|
|
|
ListScope D(W, "Relocations");
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const RelocationRef &Reloc : Sec.relocations())
|
|
|
|
printRelocation(Sec, Reloc);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (opts::SectionSymbols) {
|
|
|
|
ListScope D(W, "Symbols");
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const SymbolRef &Symbol : Obj->symbols()) {
|
2014-10-08 23:28:58 +08:00
|
|
|
if (!Sec.containsSymbol(Symbol))
|
2013-04-04 02:31:38 +08:00
|
|
|
continue;
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
printSymbol(Symbol);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-27 06:32:16 +08:00
|
|
|
if (opts::SectionData &&
|
|
|
|
!(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
|
2013-04-04 02:31:38 +08:00
|
|
|
StringRef Data;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Sec.getContents(Data));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
W.printBinaryBlock("SectionData", Data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printRelocations() {
|
|
|
|
ListScope D(W, "Relocations");
|
|
|
|
|
|
|
|
int SectionNumber = 0;
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
++SectionNumber;
|
|
|
|
StringRef Name;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Section.getName(Name));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
bool PrintedGroup = false;
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const RelocationRef &Reloc : Section.relocations()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
if (!PrintedGroup) {
|
|
|
|
W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
|
|
|
|
W.indent();
|
|
|
|
PrintedGroup = true;
|
|
|
|
}
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
printRelocation(Section, Reloc);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PrintedGroup) {
|
|
|
|
W.unindent();
|
|
|
|
W.startLine() << "}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
void COFFDumper::printRelocation(const SectionRef &Section,
|
2016-01-15 01:51:57 +08:00
|
|
|
const RelocationRef &Reloc, uint64_t Bias) {
|
|
|
|
uint64_t Offset = Reloc.getOffset() - Bias;
|
2015-06-30 09:53:01 +08:00
|
|
|
uint64_t RelocType = Reloc.getType();
|
2013-04-04 02:31:38 +08:00
|
|
|
SmallString<32> RelocName;
|
|
|
|
StringRef SymbolName;
|
2015-06-30 12:08:37 +08:00
|
|
|
Reloc.getTypeName(RelocName);
|
2014-03-14 22:22:49 +08:00
|
|
|
symbol_iterator Symbol = Reloc.getSymbol();
|
2015-07-03 04:55:21 +08:00
|
|
|
if (Symbol != Obj->symbol_end()) {
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> SymbolNameOrErr = Symbol->getName();
|
|
|
|
error(errorToErrorCode(SymbolNameOrErr.takeError()));
|
2015-07-03 04:55:21 +08:00
|
|
|
SymbolName = *SymbolNameOrErr;
|
|
|
|
}
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2013-04-12 12:01:52 +08:00
|
|
|
if (opts::ExpandRelocs) {
|
|
|
|
DictScope Group(W, "Relocation");
|
|
|
|
W.printHex("Offset", Offset);
|
|
|
|
W.printNumber("Type", RelocName, RelocType);
|
2014-11-13 15:42:11 +08:00
|
|
|
W.printString("Symbol", SymbolName.empty() ? "-" : SymbolName);
|
2013-04-12 12:01:52 +08:00
|
|
|
} else {
|
|
|
|
raw_ostream& OS = W.startLine();
|
|
|
|
OS << W.hex(Offset)
|
|
|
|
<< " " << RelocName
|
2014-11-13 15:42:11 +08:00
|
|
|
<< " " << (SymbolName.empty() ? "-" : SymbolName)
|
2013-04-12 12:01:52 +08:00
|
|
|
<< "\n";
|
|
|
|
}
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printSymbols() {
|
|
|
|
ListScope Group(W, "Symbols");
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
for (const SymbolRef &Symbol : Obj->symbols())
|
|
|
|
printSymbol(Symbol);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static ErrorOr<StringRef>
|
2014-11-17 19:17:17 +08:00
|
|
|
getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
|
|
|
|
const coff_section *Section) {
|
2014-09-20 08:25:06 +08:00
|
|
|
if (Section) {
|
|
|
|
StringRef SectionName;
|
2014-11-17 19:17:17 +08:00
|
|
|
if (std::error_code EC = Obj->getSectionName(Section, SectionName))
|
|
|
|
return EC;
|
2014-09-20 08:25:06 +08:00
|
|
|
return SectionName;
|
|
|
|
}
|
|
|
|
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
|
2014-11-17 19:17:17 +08:00
|
|
|
return StringRef("IMAGE_SYM_DEBUG");
|
2014-09-20 08:25:06 +08:00
|
|
|
if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE)
|
2014-11-17 19:17:17 +08:00
|
|
|
return StringRef("IMAGE_SYM_ABSOLUTE");
|
2014-09-20 08:25:06 +08:00
|
|
|
if (SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
|
2014-11-17 19:17:17 +08:00
|
|
|
return StringRef("IMAGE_SYM_UNDEFINED");
|
|
|
|
return StringRef("");
|
2014-09-20 08:25:06 +08:00
|
|
|
}
|
|
|
|
|
2014-03-18 14:53:02 +08:00
|
|
|
void COFFDumper::printSymbol(const SymbolRef &Sym) {
|
2013-04-04 02:31:38 +08:00
|
|
|
DictScope D(W, "Symbol");
|
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym);
|
2013-04-04 02:31:38 +08:00
|
|
|
const coff_section *Section;
|
2014-09-10 20:51:52 +08:00
|
|
|
if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) {
|
2013-04-04 02:31:38 +08:00
|
|
|
W.startLine() << "Invalid section number: " << EC.message() << "\n";
|
|
|
|
W.flush();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef SymbolName;
|
|
|
|
if (Obj->getSymbolName(Symbol, SymbolName))
|
|
|
|
SymbolName = "";
|
|
|
|
|
2014-11-17 19:17:17 +08:00
|
|
|
StringRef SectionName = "";
|
|
|
|
ErrorOr<StringRef> Res =
|
|
|
|
getSectionName(Obj, Symbol.getSectionNumber(), Section);
|
|
|
|
if (Res)
|
|
|
|
SectionName = *Res;
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
W.printString("Name", SymbolName);
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printNumber("Value", Symbol.getValue());
|
|
|
|
W.printNumber("Section", SectionName, Symbol.getSectionNumber());
|
|
|
|
W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType));
|
|
|
|
W.printEnum ("ComplexType", Symbol.getComplexType(),
|
2013-04-04 02:31:38 +08:00
|
|
|
makeArrayRef(ImageSymDType));
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printEnum ("StorageClass", Symbol.getStorageClass(),
|
2013-04-04 02:31:38 +08:00
|
|
|
makeArrayRef(ImageSymClass));
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols());
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {
|
|
|
|
if (Symbol.isFunctionDefinition()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
const coff_aux_function_definition *Aux;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(getSymbolAuxData(Obj, Symbol, I, Aux));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
DictScope AS(W, "AuxFunctionDef");
|
|
|
|
W.printNumber("TagIndex", Aux->TagIndex);
|
|
|
|
W.printNumber("TotalSize", Aux->TotalSize);
|
2014-03-19 12:33:27 +08:00
|
|
|
W.printHex("PointerToLineNumber", Aux->PointerToLinenumber);
|
2013-04-04 02:31:38 +08:00
|
|
|
W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
|
|
|
|
|
2014-10-31 13:07:00 +08:00
|
|
|
} else if (Symbol.isAnyUndefined()) {
|
2014-03-19 12:33:27 +08:00
|
|
|
const coff_aux_weak_external *Aux;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(getSymbolAuxData(Obj, Symbol, I, Aux));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex);
|
2013-04-04 02:31:38 +08:00
|
|
|
StringRef LinkedName;
|
2014-09-10 20:51:52 +08:00
|
|
|
std::error_code EC = Linked.getError();
|
|
|
|
if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) {
|
2013-04-04 02:31:38 +08:00
|
|
|
LinkedName = "";
|
|
|
|
error(EC);
|
|
|
|
}
|
|
|
|
|
|
|
|
DictScope AS(W, "AuxWeakExternal");
|
|
|
|
W.printNumber("Linked", LinkedName, Aux->TagIndex);
|
|
|
|
W.printEnum ("Search", Aux->Characteristics,
|
|
|
|
makeArrayRef(WeakExternalCharacteristics));
|
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
} else if (Symbol.isFileRecord()) {
|
|
|
|
const char *FileName;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(getSymbolAuxData(Obj, Symbol, I, FileName));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2013-04-22 16:35:11 +08:00
|
|
|
DictScope AS(W, "AuxFileRecord");
|
2014-04-14 10:37:23 +08:00
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() *
|
|
|
|
Obj->getSymbolTableEntrySize());
|
2014-04-14 10:37:23 +08:00
|
|
|
W.printString("FileName", Name.rtrim(StringRef("\0", 1)));
|
2014-04-16 12:15:29 +08:00
|
|
|
break;
|
2014-09-10 20:51:52 +08:00
|
|
|
} else if (Symbol.isSectionDefinition()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
const coff_aux_section_definition *Aux;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(getSymbolAuxData(Obj, Symbol, I, Aux));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-09-16 03:42:42 +08:00
|
|
|
int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj());
|
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
DictScope AS(W, "AuxSectionDef");
|
|
|
|
W.printNumber("Length", Aux->Length);
|
|
|
|
W.printNumber("RelocationCount", Aux->NumberOfRelocations);
|
|
|
|
W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
|
|
|
|
W.printHex("Checksum", Aux->CheckSum);
|
2014-09-16 03:42:42 +08:00
|
|
|
W.printNumber("Number", AuxNumber);
|
2013-04-04 02:31:38 +08:00
|
|
|
W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
|
|
|
|
|
2013-04-22 16:34:59 +08:00
|
|
|
if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
|
2013-04-04 02:31:38 +08:00
|
|
|
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
|
|
|
const coff_section *Assoc;
|
2014-11-17 19:17:17 +08:00
|
|
|
StringRef AssocName = "";
|
|
|
|
std::error_code EC = Obj->getSection(AuxNumber, Assoc);
|
|
|
|
ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
|
|
|
|
if (Res)
|
|
|
|
AssocName = *Res;
|
|
|
|
if (!EC)
|
|
|
|
EC = Res.getError();
|
|
|
|
if (EC) {
|
2013-04-04 02:31:38 +08:00
|
|
|
AssocName = "";
|
|
|
|
error(EC);
|
|
|
|
}
|
|
|
|
|
2014-09-16 03:42:42 +08:00
|
|
|
W.printNumber("AssocSection", AssocName, AuxNumber);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
2014-09-10 20:51:52 +08:00
|
|
|
} else if (Symbol.isCLRToken()) {
|
2013-04-04 02:31:38 +08:00
|
|
|
const coff_aux_clr_token *Aux;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(getSymbolAuxData(Obj, Symbol, I, Aux));
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
ErrorOr<COFFSymbolRef> ReferredSym =
|
|
|
|
Obj->getSymbol(Aux->SymbolTableIndex);
|
2014-03-17 09:46:52 +08:00
|
|
|
StringRef ReferredName;
|
2014-09-10 20:51:52 +08:00
|
|
|
std::error_code EC = ReferredSym.getError();
|
|
|
|
if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) {
|
2014-03-17 09:46:52 +08:00
|
|
|
ReferredName = "";
|
|
|
|
error(EC);
|
|
|
|
}
|
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
DictScope AS(W, "AuxCLRToken");
|
|
|
|
W.printNumber("AuxType", Aux->AuxType);
|
|
|
|
W.printNumber("Reserved", Aux->Reserved);
|
2014-03-17 09:46:52 +08:00
|
|
|
W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex);
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
W.startLine() << "<unhandled auxiliary record>\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printUnwindInfo() {
|
|
|
|
ListScope D(W, "UnwindInformation");
|
2014-09-10 20:51:52 +08:00
|
|
|
switch (Obj->getMachine()) {
|
2014-05-26 04:26:45 +08:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_AMD64: {
|
|
|
|
Win64EH::Dumper Dumper(W);
|
2014-06-13 11:07:50 +08:00
|
|
|
Win64EH::Dumper::SymbolResolver
|
|
|
|
Resolver = [](const object::coff_section *Section, uint64_t Offset,
|
|
|
|
SymbolRef &Symbol, void *user_data) -> std::error_code {
|
|
|
|
COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data);
|
|
|
|
return Dumper->resolveSymbol(Section, Offset, Symbol);
|
|
|
|
};
|
2014-05-26 05:37:59 +08:00
|
|
|
Win64EH::Dumper::Context Ctx(*Obj, Resolver, this);
|
2014-05-26 04:26:45 +08:00
|
|
|
Dumper.printData(Ctx);
|
2013-04-04 02:31:38 +08:00
|
|
|
break;
|
2014-05-26 04:26:45 +08:00
|
|
|
}
|
2014-06-04 23:47:15 +08:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT: {
|
|
|
|
ARM::WinEH::Decoder Decoder(W);
|
|
|
|
Decoder.dumpProcedureData(*Obj);
|
|
|
|
break;
|
|
|
|
}
|
2014-05-26 04:26:45 +08:00
|
|
|
default:
|
2014-09-10 20:51:52 +08:00
|
|
|
W.printEnum("unsupported Image Machine", Obj->getMachine(),
|
2014-05-26 04:26:45 +08:00
|
|
|
makeArrayRef(ImageFileMachineType));
|
2013-04-04 02:31:38 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-05-26 04:26:45 +08:00
|
|
|
|
2014-10-09 10:16:38 +08:00
|
|
|
void COFFDumper::printImportedSymbols(
|
|
|
|
iterator_range<imported_symbol_iterator> Range) {
|
|
|
|
for (const ImportedSymbolRef &I : Range) {
|
2014-10-03 08:41:58 +08:00
|
|
|
StringRef Sym;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getSymbolName(Sym));
|
2014-10-03 08:41:58 +08:00
|
|
|
uint16_t Ordinal;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getOrdinal(Ordinal));
|
2014-10-03 08:41:58 +08:00
|
|
|
W.printNumber("Symbol", Sym, Ordinal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-13 11:22:54 +08:00
|
|
|
void COFFDumper::printDelayImportedSymbols(
|
|
|
|
const DelayImportDirectoryEntryRef &I,
|
|
|
|
iterator_range<imported_symbol_iterator> Range) {
|
|
|
|
int Index = 0;
|
|
|
|
for (const ImportedSymbolRef &S : Range) {
|
|
|
|
DictScope Import(W, "Import");
|
|
|
|
StringRef Sym;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(S.getSymbolName(Sym));
|
2014-11-13 11:22:54 +08:00
|
|
|
uint16_t Ordinal;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(S.getOrdinal(Ordinal));
|
2014-11-13 11:22:54 +08:00
|
|
|
W.printNumber("Symbol", Sym, Ordinal);
|
|
|
|
uint64_t Addr;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getImportAddress(Index++, Addr));
|
2014-11-13 11:22:54 +08:00
|
|
|
W.printHex("Address", Addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-03 01:02:18 +08:00
|
|
|
void COFFDumper::printCOFFImports() {
|
2014-10-03 08:41:58 +08:00
|
|
|
// Regular imports
|
2014-10-09 10:16:38 +08:00
|
|
|
for (const ImportDirectoryEntryRef &I : Obj->import_directories()) {
|
2014-10-03 01:02:18 +08:00
|
|
|
DictScope Import(W, "Import");
|
|
|
|
StringRef Name;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getName(Name));
|
2014-10-03 01:02:18 +08:00
|
|
|
W.printString("Name", Name);
|
2017-03-27 01:10:11 +08:00
|
|
|
uint32_t ILTAddr;
|
|
|
|
error(I.getImportLookupTableRVA(ILTAddr));
|
|
|
|
W.printHex("ImportLookupTableRVA", ILTAddr);
|
|
|
|
uint32_t IATAddr;
|
|
|
|
error(I.getImportAddressTableRVA(IATAddr));
|
|
|
|
W.printHex("ImportAddressTableRVA", IATAddr);
|
|
|
|
// The import lookup table can be missing with certain older linkers, so
|
|
|
|
// fall back to the import address table in that case.
|
|
|
|
if (ILTAddr)
|
|
|
|
printImportedSymbols(I.lookup_table_symbols());
|
|
|
|
else
|
|
|
|
printImportedSymbols(I.imported_symbols());
|
2014-10-03 08:41:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Delay imports
|
2014-10-09 10:16:38 +08:00
|
|
|
for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) {
|
2014-10-03 08:41:58 +08:00
|
|
|
DictScope Import(W, "DelayImport");
|
|
|
|
StringRef Name;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getName(Name));
|
2014-10-03 08:41:58 +08:00
|
|
|
W.printString("Name", Name);
|
2014-10-04 02:07:18 +08:00
|
|
|
const delay_import_directory_table_entry *Table;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getDelayImportTable(Table));
|
2014-10-04 02:07:18 +08:00
|
|
|
W.printHex("Attributes", Table->Attributes);
|
|
|
|
W.printHex("ModuleHandle", Table->ModuleHandle);
|
|
|
|
W.printHex("ImportAddressTable", Table->DelayImportAddressTable);
|
|
|
|
W.printHex("ImportNameTable", Table->DelayImportNameTable);
|
|
|
|
W.printHex("BoundDelayImportTable", Table->BoundDelayImportTable);
|
|
|
|
W.printHex("UnloadDelayImportTable", Table->UnloadDelayImportTable);
|
2014-11-13 11:22:54 +08:00
|
|
|
printDelayImportedSymbols(I, I.imported_symbols());
|
2014-10-03 01:02:18 +08:00
|
|
|
}
|
|
|
|
}
|
2014-10-08 03:37:52 +08:00
|
|
|
|
2015-01-04 05:35:09 +08:00
|
|
|
void COFFDumper::printCOFFExports() {
|
|
|
|
for (const ExportDirectoryEntryRef &E : Obj->export_directories()) {
|
|
|
|
DictScope Export(W, "Export");
|
|
|
|
|
|
|
|
StringRef Name;
|
|
|
|
uint32_t Ordinal, RVA;
|
|
|
|
|
2015-07-20 11:23:55 +08:00
|
|
|
error(E.getSymbolName(Name));
|
|
|
|
error(E.getOrdinal(Ordinal));
|
|
|
|
error(E.getExportRVA(RVA));
|
2015-01-04 05:35:09 +08:00
|
|
|
|
|
|
|
W.printNumber("Ordinal", Ordinal);
|
|
|
|
W.printString("Name", Name);
|
|
|
|
W.printHex("RVA", RVA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-08 03:37:52 +08:00
|
|
|
void COFFDumper::printCOFFDirectives() {
|
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
|
|
|
StringRef Contents;
|
|
|
|
StringRef Name;
|
|
|
|
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Section.getName(Name));
|
2014-10-08 03:37:52 +08:00
|
|
|
if (Name != ".drectve")
|
|
|
|
continue;
|
|
|
|
|
2015-07-20 11:23:55 +08:00
|
|
|
error(Section.getContents(Contents));
|
2014-10-08 03:37:52 +08:00
|
|
|
|
|
|
|
W.printString("Directive(s)", Contents);
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 08:18:07 +08:00
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static StringRef getBaseRelocTypeName(uint8_t Type) {
|
2014-11-19 08:18:07 +08:00
|
|
|
switch (Type) {
|
|
|
|
case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE";
|
|
|
|
case COFF::IMAGE_REL_BASED_HIGH: return "HIGH";
|
|
|
|
case COFF::IMAGE_REL_BASED_LOW: return "LOW";
|
|
|
|
case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW";
|
|
|
|
case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ";
|
2015-01-17 04:16:09 +08:00
|
|
|
case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)";
|
2014-11-19 08:18:07 +08:00
|
|
|
case COFF::IMAGE_REL_BASED_DIR64: return "DIR64";
|
2014-11-20 01:10:39 +08:00
|
|
|
default: return "unknown (" + llvm::utostr(Type) + ")";
|
2014-11-19 08:18:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printCOFFBaseReloc() {
|
|
|
|
ListScope D(W, "BaseReloc");
|
|
|
|
for (const BaseRelocRef &I : Obj->base_relocs()) {
|
|
|
|
uint8_t Type;
|
|
|
|
uint32_t RVA;
|
2015-07-20 11:23:55 +08:00
|
|
|
error(I.getRVA(RVA));
|
|
|
|
error(I.getType(Type));
|
2014-11-19 08:18:07 +08:00
|
|
|
DictScope Import(W, "Entry");
|
|
|
|
W.printString("Type", getBaseRelocTypeName(Type));
|
|
|
|
W.printHex("Address", RVA);
|
|
|
|
}
|
|
|
|
}
|
2015-06-27 07:56:53 +08:00
|
|
|
|
2017-04-28 03:38:38 +08:00
|
|
|
void COFFDumper::printCOFFResources() {
|
|
|
|
ListScope ResourcesD(W, "Resources");
|
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
|
|
|
StringRef Name;
|
|
|
|
error(S.getName(Name));
|
|
|
|
if (!Name.startswith(".rsrc"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
StringRef Ref;
|
|
|
|
error(S.getContents(Ref));
|
|
|
|
|
|
|
|
if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
|
|
|
|
auto Table =
|
|
|
|
reinterpret_cast<const coff_resource_dir_table *>(Ref.data());
|
|
|
|
char FormattedTime[20];
|
|
|
|
time_t TDS = time_t(Table->TimeDateStamp);
|
|
|
|
strftime(FormattedTime, sizeof(FormattedTime), "%Y-%m-%d %H:%M:%S",
|
|
|
|
gmtime(&TDS));
|
|
|
|
W.printHex("Time/Date Stamp", FormattedTime, Table->TimeDateStamp);
|
|
|
|
}
|
|
|
|
W.printBinaryBlock(Name.str() + " Data", Ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 07:56:53 +08:00
|
|
|
void COFFDumper::printStackMap() const {
|
|
|
|
object::SectionRef StackMapSection;
|
|
|
|
for (auto Sec : Obj->sections()) {
|
|
|
|
StringRef Name;
|
|
|
|
Sec.getName(Name);
|
|
|
|
if (Name == ".llvm_stackmaps") {
|
|
|
|
StackMapSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StackMapSection == object::SectionRef())
|
|
|
|
return;
|
|
|
|
|
|
|
|
StringRef StackMapContents;
|
|
|
|
StackMapSection.getContents(StackMapContents);
|
|
|
|
ArrayRef<uint8_t> StackMapContentsArray(
|
|
|
|
reinterpret_cast<const uint8_t*>(StackMapContents.data()),
|
|
|
|
StackMapContents.size());
|
|
|
|
|
|
|
|
if (Obj->isLittleEndian())
|
|
|
|
prettyPrintStackMap(
|
|
|
|
llvm::outs(),
|
2016-09-15 04:22:03 +08:00
|
|
|
StackMapV2Parser<support::little>(StackMapContentsArray));
|
2015-06-27 07:56:53 +08:00
|
|
|
else
|
|
|
|
prettyPrintStackMap(llvm::outs(),
|
2016-09-15 04:22:03 +08:00
|
|
|
StackMapV2Parser<support::big>(StackMapContentsArray));
|
2015-06-27 07:56:53 +08:00
|
|
|
}
|
2016-05-14 08:02:53 +08:00
|
|
|
|
2016-11-09 06:24:53 +08:00
|
|
|
void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
|
2017-03-25 01:26:38 +08:00
|
|
|
llvm::codeview::TypeTableBuilder &IDTable,
|
2016-11-09 06:24:53 +08:00
|
|
|
llvm::codeview::TypeTableBuilder &CVTypes) {
|
2016-05-14 08:02:53 +08:00
|
|
|
// Flatten it first, then run our dumper on it.
|
2017-03-25 01:26:38 +08:00
|
|
|
SmallString<0> TypeBuf;
|
2016-11-09 06:24:53 +08:00
|
|
|
CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
|
2017-03-25 01:26:38 +08:00
|
|
|
TypeBuf.append(Record.begin(), Record.end());
|
2016-05-14 08:02:53 +08:00
|
|
|
});
|
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.
Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.
All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.
After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.
Differential Revision: https://reviews.llvm.org/D28524
llvm-svn: 291724
2017-01-12 07:24:22 +08:00
|
|
|
|
|
|
|
TypeDatabase TypeDB;
|
2017-03-25 01:26:38 +08:00
|
|
|
{
|
|
|
|
ListScope S(Writer, "MergedTypeStream");
|
|
|
|
CVTypeDumper CVTD(TypeDB);
|
|
|
|
TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
|
|
|
|
if (auto EC = CVTD.dump(
|
|
|
|
{TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
|
|
|
|
Writer.flush();
|
2017-04-04 07:58:15 +08:00
|
|
|
error(std::move(EC));
|
2017-03-25 01:26:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flatten the id stream and print it next. The ID stream refers to names from
|
|
|
|
// the type stream.
|
|
|
|
SmallString<0> IDBuf;
|
|
|
|
IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
|
|
|
|
IDBuf.append(Record.begin(), Record.end());
|
|
|
|
});
|
|
|
|
|
|
|
|
{
|
|
|
|
ListScope S(Writer, "MergedIDStream");
|
|
|
|
TypeDatabase IDDB;
|
|
|
|
CVTypeDumper CVTD(IDDB);
|
|
|
|
TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
|
|
|
|
TDV.setItemDB(IDDB);
|
|
|
|
if (auto EC = CVTD.dump(
|
|
|
|
{IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
|
|
|
|
Writer.flush();
|
2017-04-04 07:58:15 +08:00
|
|
|
error(std::move(EC));
|
2017-03-25 01:26:38 +08:00
|
|
|
}
|
2016-05-14 08:02:53 +08:00
|
|
|
}
|
|
|
|
}
|