2013-04-04 02:31:38 +08:00
|
|
|
//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-04-04 02:31:38 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
2018-05-01 23:54:18 +08:00
|
|
|
/// This file implements the COFF-specific dumper for llvm-readobj.
|
2013-04-04 02:31:38 +08:00
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-06-13 01:38:55 +08:00
|
|
|
#include "ARMWinEHPrinter.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-06-07 11:48:56 +08:00
|
|
|
#include "llvm/BinaryFormat/COFF.h"
|
2017-05-20 03:26:58 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
2016-01-14 07:44:57 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
2017-05-31 00:36:15 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
2017-05-31 01:13:33 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
|
2017-05-31 00:36:15 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
|
2017-05-31 01:13:33 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
|
2017-05-20 03:26:58 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
2016-01-15 03:20:17 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/Line.h"
|
2017-12-01 02:39:50 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
|
2016-05-24 07:41:13 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
|
|
|
#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"
|
2017-12-06 07:58:18 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeHashing.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"
|
2017-05-20 03:26:58 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2019-04-25 07:26:30 +08:00
|
|
|
#include "llvm/Object/WindowsResource.h"
|
2017-04-29 07:41:36 +08:00
|
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
[CodeView] Provide a common interface for type collections.
Right now we have multiple notions of things that represent collections of
types. Most commonly used are TypeDatabase, which is supposed to keep
mappings from TypeIndex to type name when reading a type stream, which
happens when reading PDBs. And also TypeTableBuilder, which is used to
build up a collection of types dynamically which we will later serialize
(i.e. when writing PDBs).
But often you just want to do some operation on a collection of types, and
you may want to do the same operation on any kind of collection. For
example, you might want to merge two TypeTableBuilders or you might want
to merge two type streams that you loaded from various files.
This dichotomy between reading and writing is responsible for a lot of the
existing code duplication and overlapping responsibilities in the existing
CodeView library classes. For example, after building up a
TypeTableBuilder with a bunch of type records, if we want to dump it we
have to re-invent a bunch of extra glue because our dumper takes a
TypeDatabase or a CVTypeArray, which are both incompatible with
TypeTableBuilder.
This patch introduces an abstract base class called TypeCollection which
is shared between the various type collection like things. Wherever we
previously stored a TypeDatabase& in some common class, we now store a
TypeCollection&.
The advantage of this is that all the details of how the collection are
implemented, such as lazy deserialization of partial type streams, is
completely transparent and you can just treat any collection of types the
same regardless of where it came from.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303388
2017-05-19 07:03:06 +08:00
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2017-04-29 07:41:36 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2018-08-23 07:58:16 +08:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2019-02-21 15:42:31 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2013-04-04 02:31:38 +08:00
|
|
|
#include "llvm/Support/Win64EH.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
2017-06-22 09:10:29 +08:00
|
|
|
struct LoadConfigTables {
|
|
|
|
uint64_t SEHTableVA = 0;
|
|
|
|
uint64_t SEHTableCount = 0;
|
|
|
|
uint32_t GuardFlags = 0;
|
|
|
|
uint64_t GuardFidTableVA = 0;
|
|
|
|
uint64_t GuardFidTableCount = 0;
|
2020-11-18 10:02:13 +08:00
|
|
|
uint64_t GuardIatTableVA = 0;
|
|
|
|
uint64_t GuardIatTableCount = 0;
|
2018-02-14 04:32:53 +08:00
|
|
|
uint64_t GuardLJmpTableVA = 0;
|
|
|
|
uint64_t GuardLJmpTableCount = 0;
|
2017-06-22 09:10:29 +08:00
|
|
|
};
|
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
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)
|
2020-11-27 18:34:30 +08:00
|
|
|
: ObjDumper(Writer, Obj->getFileName()), Obj(Obj), Writer(Writer),
|
|
|
|
Types(100) {}
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2014-08-31 00:48:34 +08:00
|
|
|
void printFileHeaders() override;
|
[llvm-readelf] Make llvm-readelf more compatible with GNU readelf.
Summary:
This change adds a bunch of options that GNU readelf supports. There is one breaking change when invoked as `llvm-readobj`, and three breaking changes when invoked as `llvm-readelf`:
- Add --all (implies --file-header, --program-headers, etc.)
- [Breaking] -a is --all instead of --arm-attributes
- Add --file-header as an alias for --file-headers
- Replace --sections with --sections-headers, keeping --sections as an alias for it
- Add --relocs as an alias for --relocations
- Add --dynamic as an alias for --dynamic-table
- Add --segments as an alias for --program-headers
- Add --section-groups as an alias for --elf-section-groups
- Add --dyn-syms as an alias for --dyn-symbols
- Add --syms as an alias for --symbols
- Add --histogram as an alias for --elf-hash-histogram
- [Breaking] When invoked as `llvm-readelf`, -s is --symbols instead of --sections
- [Breaking] When invoked as `llvm-readelf`, -t is no longer an alias for --symbols
Reviewers: MaskRay, phosek, mcgrathr, jhenderson
Reviewed By: MaskRay, jhenderson
Subscribers: sbc100, aheejin, edd, jhenderson, silvas, echristo, compnerd, kristina, javed.absar, kristof.beyls, llvm-commits, Bigcheese
Differential Revision: https://reviews.llvm.org/D54124
llvm-svn: 346685
2018-11-13 02:02:38 +08:00
|
|
|
void printSectionHeaders() override;
|
2014-08-31 00:48:34 +08:00
|
|
|
void printRelocations() override;
|
|
|
|
void printUnwindInfo() override;
|
2017-12-28 03:59:56 +08:00
|
|
|
|
|
|
|
void printNeededLibraries() 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;
|
2020-10-08 16:43:50 +08:00
|
|
|
void printCOFFTLSDirectory() override;
|
2017-04-28 03:38:38 +08:00
|
|
|
void printCOFFResources() override;
|
2017-06-22 09:10:29 +08:00
|
|
|
void printCOFFLoadConfig() override;
|
2015-12-17 02:28:12 +08:00
|
|
|
void printCodeViewDebugInfo() override;
|
2019-02-07 23:24:18 +08:00
|
|
|
void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
|
|
|
|
llvm::codeview::MergingTypeTableBuilder &CVTypes,
|
|
|
|
llvm::codeview::GlobalTypeTableBuilder &GlobalCVIDs,
|
|
|
|
llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
|
|
|
|
bool GHash) override;
|
2015-06-27 07:56:53 +08:00
|
|
|
void printStackMap() const override;
|
2018-08-23 07:58:16 +08:00
|
|
|
void printAddrsig() override;
|
2020-06-16 07:29:36 +08:00
|
|
|
void printCGProfile() override;
|
2020-03-13 18:41:18 +08:00
|
|
|
|
2013-04-04 02:31:38 +08:00
|
|
|
private:
|
2020-06-16 07:29:36 +08:00
|
|
|
StringRef getSymbolName(uint32_t Index);
|
2019-01-24 00:15:39 +08:00
|
|
|
void printSymbols() override;
|
|
|
|
void printDynamicSymbols() override;
|
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);
|
2017-06-22 09:10:29 +08:00
|
|
|
template <typename T>
|
|
|
|
void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
|
2020-10-08 16:43:50 +08:00
|
|
|
template <typename IntTy>
|
|
|
|
void printCOFFTLSDirectory(const coff_tls_directory<IntTy> *TlsTable);
|
2017-06-22 09:10:29 +08:00
|
|
|
typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
|
|
|
|
void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
|
|
|
|
PrintExtraCB PrintExtra = 0);
|
2014-01-26 12:15:52 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
|
|
|
|
void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
|
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.
|
2017-05-20 03:26:58 +08:00
|
|
|
codeview::printTypeIndex(Writer, FieldName, TI, Types);
|
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);
|
|
|
|
|
2017-06-13 08:16:32 +08:00
|
|
|
uint32_t countTotalTableEntries(ResourceSectionRef RSF,
|
|
|
|
const coff_resource_dir_table &Table,
|
|
|
|
StringRef Level);
|
|
|
|
|
2017-05-08 10:47:07 +08:00
|
|
|
void printResourceDirectoryTable(ResourceSectionRef RSF,
|
|
|
|
const coff_resource_dir_table &Table,
|
|
|
|
StringRef Level);
|
|
|
|
|
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.
|
2017-05-04 01:11:11 +08:00
|
|
|
void initializeFileAndStringTables(BinaryStreamReader &Reader);
|
2016-01-15 08:11:21 +08:00
|
|
|
|
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;
|
2017-05-04 01:11:11 +08:00
|
|
|
|
2017-05-31 01:13:33 +08:00
|
|
|
DebugChecksumsSubsectionRef CVFileChecksumTable;
|
2017-05-04 01:11:11 +08:00
|
|
|
|
2017-05-31 01:13:33 +08:00
|
|
|
DebugStringTableSubsectionRef CVStringTable;
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2018-09-12 06:00:50 +08:00
|
|
|
/// Track the compilation CPU type. S_COMPILE3 symbol records typically come
|
|
|
|
/// first, but if we don't see one, just assume an X64 CPU type. It is common.
|
|
|
|
CPUType CompilationCPUType = CPUType::X64;
|
|
|
|
|
[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;
|
2017-05-20 03:26:58 +08:00
|
|
|
BinaryByteStream TypeContents;
|
|
|
|
LazyRandomTypeCollection Types;
|
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);
|
|
|
|
}
|
|
|
|
|
2017-05-31 01:13:33 +08:00
|
|
|
DebugStringTableSubsectionRef getStringTable() override {
|
|
|
|
return CD.CVStringTable;
|
|
|
|
}
|
2016-05-24 07:41:13 +08:00
|
|
|
|
|
|
|
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 {
|
|
|
|
|
2020-08-27 23:20:13 +08:00
|
|
|
std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj,
|
|
|
|
ScopedPrinter &Writer) {
|
|
|
|
return std::make_unique<COFFDumper>(&Obj, Writer);
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
} // namespace llvm
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2018-02-22 15:48:29 +08:00
|
|
|
// Given a section and an offset into this section the function returns the
|
2014-05-26 04:26:37 +08:00
|
|
|
// 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())
|
2020-08-28 17:18:19 +08:00
|
|
|
return inconvertibleErrorCode();
|
2016-05-29 14:18:08 +08:00
|
|
|
Sym = *SymI;
|
2020-08-28 17:18:19 +08:00
|
|
|
return std::error_code();
|
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 ),
|
2017-06-30 15:02:13 +08:00
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64 ),
|
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),
|
|
|
|
};
|
|
|
|
|
2020-03-13 18:41:18 +08:00
|
|
|
static const EnumEntry<COFF::ExtendedDLLCharacteristics>
|
|
|
|
PEExtendedDLLCharacteristics[] = {
|
|
|
|
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT),
|
|
|
|
};
|
|
|
|
|
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[] = {
|
2020-03-13 18:41:18 +08:00
|
|
|
{"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},
|
|
|
|
{"Reserved10", COFF::IMAGE_DEBUG_TYPE_RESERVED10},
|
|
|
|
{"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},
|
|
|
|
{"Repro", COFF::IMAGE_DEBUG_TYPE_REPRO},
|
|
|
|
{"ExtendedDLLCharacteristics",
|
|
|
|
COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS},
|
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-05-31 00:36:15 +08:00
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Lines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput),
|
|
|
|
LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, 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());
|
2020-08-28 17:18:19 +08:00
|
|
|
return std::error_code();
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2019-05-02 18:49:27 +08:00
|
|
|
llvm::sort(RelocMap[Section], [](RelocationRef L, RelocationRef R) {
|
|
|
|
return L.getOffset() < R.getOffset();
|
|
|
|
});
|
2013-04-04 02:31:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 19:44:10 +08:00
|
|
|
void COFFDumper::printDataDirectory(uint32_t Index,
|
|
|
|
const std::string &FieldName) {
|
2020-06-12 04:00:54 +08:00
|
|
|
const data_directory *Data = Obj->getDataDirectory(Index);
|
|
|
|
if (!Data)
|
2013-07-20 07:23:29 +08:00
|
|
|
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());
|
2020-05-07 06:36:18 +08:00
|
|
|
W.printNumber("StringTableSize", Obj->getStringTableSize());
|
2014-09-10 20:51:52 +08:00
|
|
|
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.
|
2019-08-19 22:32:23 +08:00
|
|
|
if (const pe32_header *PEHeader = Obj->getPE32Header())
|
2014-01-26 12:15:52 +08:00
|
|
|
printPEHeader<pe32_header>(PEHeader);
|
|
|
|
|
2019-08-19 22:32:23 +08:00
|
|
|
if (const pe32plus_header *PEPlusHeader = Obj->getPE32PlusHeader())
|
2014-01-26 12:15:52 +08:00
|
|
|
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");
|
2017-06-30 15:02:04 +08:00
|
|
|
W.printHex ("Magic", Hdr->Magic);
|
2014-01-26 12:15:52 +08:00
|
|
|
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);
|
2020-04-27 19:55:31 +08:00
|
|
|
// Ideally, if D.AddressOfRawData == 0, we should try to load the payload
|
|
|
|
// using D.PointerToRawData instead.
|
|
|
|
if (D.AddressOfRawData == 0)
|
|
|
|
continue;
|
2016-06-03 01:10:43 +08:00
|
|
|
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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
|
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);
|
|
|
|
}
|
2018-09-06 02:01:04 +08:00
|
|
|
} else if (D.SizeOfData != 0) {
|
2020-03-13 18:41:18 +08:00
|
|
|
// FIXME: Data visualization for IMAGE_DEBUG_TYPE_VC_FEATURE and
|
|
|
|
// IMAGE_DEBUG_TYPE_POGO?
|
2016-06-03 01:10:43 +08:00
|
|
|
ArrayRef<uint8_t> RawData;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = Obj->getRvaAndSizeAsBytes(D.AddressOfRawData,
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
D.SizeOfData, RawData))
|
2020-06-12 04:00:54 +08:00
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2020-03-13 18:41:18 +08:00
|
|
|
if (D.Type == COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS) {
|
|
|
|
// FIXME right now the only possible value would fit in 8 bits,
|
|
|
|
// but that might change in the future
|
|
|
|
uint16_t Characteristics = RawData[0];
|
|
|
|
W.printFlags("ExtendedCharacteristics", Characteristics,
|
|
|
|
makeArrayRef(PEExtendedDLLCharacteristics));
|
|
|
|
}
|
2016-06-03 01:10:43 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-06-22 09:10:29 +08:00
|
|
|
void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
|
|
|
|
uint64_t EntrySize, PrintExtraCB PrintExtra) {
|
|
|
|
uintptr_t TableStart, TableEnd;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = Obj->getVaPtr(TableVA, TableStart))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E =
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd))
|
2020-06-12 04:00:54 +08:00
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-06-24 06:12:11 +08:00
|
|
|
TableEnd++;
|
2017-06-22 09:10:29 +08:00
|
|
|
for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
|
|
|
|
uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
|
|
|
|
raw_ostream &OS = W.startLine();
|
2018-01-24 07:17:06 +08:00
|
|
|
OS << W.hex(Obj->getImageBase() + RVA);
|
2017-06-22 09:10:29 +08:00
|
|
|
if (PrintExtra)
|
|
|
|
PrintExtra(OS, reinterpret_cast<const uint8_t *>(I));
|
|
|
|
OS << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printCOFFLoadConfig() {
|
|
|
|
LoadConfigTables Tables;
|
|
|
|
if (Obj->is64())
|
|
|
|
printCOFFLoadConfig(Obj->getLoadConfig64(), Tables);
|
|
|
|
else
|
|
|
|
printCOFFLoadConfig(Obj->getLoadConfig32(), Tables);
|
|
|
|
|
|
|
|
if (Tables.SEHTableVA) {
|
|
|
|
ListScope LS(W, "SEHTable");
|
|
|
|
printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tables.GuardFidTableVA) {
|
|
|
|
ListScope LS(W, "GuardFidTable");
|
|
|
|
if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) {
|
|
|
|
auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
|
|
|
|
uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
|
|
|
|
if (Flags)
|
|
|
|
OS << " flags " << utohexstr(Flags);
|
|
|
|
};
|
|
|
|
printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
|
|
|
|
PrintGuardFlags);
|
|
|
|
} else {
|
|
|
|
printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 04:32:53 +08:00
|
|
|
|
2020-11-18 10:02:13 +08:00
|
|
|
if (Tables.GuardIatTableVA) {
|
|
|
|
ListScope LS(W, "GuardIatTable");
|
|
|
|
printRVATable(Tables.GuardIatTableVA, Tables.GuardIatTableCount, 4);
|
|
|
|
}
|
|
|
|
|
2018-02-14 04:32:53 +08:00
|
|
|
if (Tables.GuardLJmpTableVA) {
|
|
|
|
ListScope LS(W, "GuardLJmpTable");
|
|
|
|
printRVATable(Tables.GuardLJmpTableVA, Tables.GuardLJmpTableCount, 4);
|
|
|
|
}
|
2017-06-22 09:10:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
|
2017-06-24 06:12:11 +08:00
|
|
|
if (!Conf)
|
|
|
|
return;
|
|
|
|
|
2017-06-22 09:10:29 +08:00
|
|
|
ListScope LS(W, "LoadConfig");
|
|
|
|
char FormattedTime[20] = {};
|
|
|
|
time_t TDS = Conf->TimeDateStamp;
|
|
|
|
strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
|
|
|
|
W.printHex("Size", Conf->Size);
|
|
|
|
|
|
|
|
// Print everything before SecurityCookie. The vast majority of images today
|
|
|
|
// have all these fields.
|
|
|
|
if (Conf->Size < offsetof(T, SEHandlerTable))
|
|
|
|
return;
|
|
|
|
W.printHex("TimeDateStamp", FormattedTime, TDS);
|
|
|
|
W.printHex("MajorVersion", Conf->MajorVersion);
|
|
|
|
W.printHex("MinorVersion", Conf->MinorVersion);
|
|
|
|
W.printHex("GlobalFlagsClear", Conf->GlobalFlagsClear);
|
|
|
|
W.printHex("GlobalFlagsSet", Conf->GlobalFlagsSet);
|
|
|
|
W.printHex("CriticalSectionDefaultTimeout",
|
|
|
|
Conf->CriticalSectionDefaultTimeout);
|
|
|
|
W.printHex("DeCommitFreeBlockThreshold", Conf->DeCommitFreeBlockThreshold);
|
|
|
|
W.printHex("DeCommitTotalFreeThreshold", Conf->DeCommitTotalFreeThreshold);
|
|
|
|
W.printHex("LockPrefixTable", Conf->LockPrefixTable);
|
|
|
|
W.printHex("MaximumAllocationSize", Conf->MaximumAllocationSize);
|
|
|
|
W.printHex("VirtualMemoryThreshold", Conf->VirtualMemoryThreshold);
|
|
|
|
W.printHex("ProcessHeapFlags", Conf->ProcessHeapFlags);
|
|
|
|
W.printHex("ProcessAffinityMask", Conf->ProcessAffinityMask);
|
|
|
|
W.printHex("CSDVersion", Conf->CSDVersion);
|
|
|
|
W.printHex("DependentLoadFlags", Conf->DependentLoadFlags);
|
|
|
|
W.printHex("EditList", Conf->EditList);
|
|
|
|
W.printHex("SecurityCookie", Conf->SecurityCookie);
|
|
|
|
|
|
|
|
// Print the safe SEH table if present.
|
|
|
|
if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction))
|
|
|
|
return;
|
|
|
|
W.printHex("SEHandlerTable", Conf->SEHandlerTable);
|
|
|
|
W.printNumber("SEHandlerCount", Conf->SEHandlerCount);
|
|
|
|
|
|
|
|
Tables.SEHTableVA = Conf->SEHandlerTable;
|
|
|
|
Tables.SEHTableCount = Conf->SEHandlerCount;
|
|
|
|
|
|
|
|
// Print everything before CodeIntegrity. (2015)
|
|
|
|
if (Conf->Size < offsetof(T, CodeIntegrity))
|
|
|
|
return;
|
|
|
|
W.printHex("GuardCFCheckFunction", Conf->GuardCFCheckFunction);
|
|
|
|
W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
|
|
|
|
W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
|
|
|
|
W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
|
|
|
|
W.printHex("GuardFlags", Conf->GuardFlags);
|
|
|
|
|
|
|
|
Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
|
|
|
|
Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
|
|
|
|
Tables.GuardFlags = Conf->GuardFlags;
|
|
|
|
|
|
|
|
// Print the rest. (2017)
|
|
|
|
if (Conf->Size < sizeof(T))
|
|
|
|
return;
|
|
|
|
W.printHex("GuardAddressTakenIatEntryTable",
|
|
|
|
Conf->GuardAddressTakenIatEntryTable);
|
|
|
|
W.printNumber("GuardAddressTakenIatEntryCount",
|
|
|
|
Conf->GuardAddressTakenIatEntryCount);
|
|
|
|
W.printHex("GuardLongJumpTargetTable", Conf->GuardLongJumpTargetTable);
|
|
|
|
W.printNumber("GuardLongJumpTargetCount", Conf->GuardLongJumpTargetCount);
|
|
|
|
W.printHex("DynamicValueRelocTable", Conf->DynamicValueRelocTable);
|
|
|
|
W.printHex("CHPEMetadataPointer", Conf->CHPEMetadataPointer);
|
|
|
|
W.printHex("GuardRFFailureRoutine", Conf->GuardRFFailureRoutine);
|
|
|
|
W.printHex("GuardRFFailureRoutineFunctionPointer",
|
|
|
|
Conf->GuardRFFailureRoutineFunctionPointer);
|
|
|
|
W.printHex("DynamicValueRelocTableOffset",
|
|
|
|
Conf->DynamicValueRelocTableOffset);
|
|
|
|
W.printNumber("DynamicValueRelocTableSection",
|
|
|
|
Conf->DynamicValueRelocTableSection);
|
|
|
|
W.printHex("GuardRFVerifyStackPointerFunctionPointer",
|
|
|
|
Conf->GuardRFVerifyStackPointerFunctionPointer);
|
|
|
|
W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset);
|
2018-02-14 04:32:53 +08:00
|
|
|
|
2020-11-18 10:02:13 +08:00
|
|
|
Tables.GuardIatTableVA = Conf->GuardAddressTakenIatEntryTable;
|
|
|
|
Tables.GuardIatTableCount = Conf->GuardAddressTakenIatEntryCount;
|
|
|
|
|
2018-02-14 04:32:53 +08:00
|
|
|
Tables.GuardLJmpTableVA = Conf->GuardLongJumpTargetTable;
|
|
|
|
Tables.GuardLJmpTableCount = Conf->GuardLongJumpTargetCount;
|
2017-06-22 09:10:29 +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()) {
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());
|
2018-04-06 02:18:12 +08:00
|
|
|
// .debug$T is a standard CodeView type section, while .debug$P is the same
|
|
|
|
// format but used for MSVC precompiled header object files.
|
|
|
|
if (SectionName == ".debug$T" || SectionName == ".debug$P")
|
2016-01-14 03:32:35 +08:00
|
|
|
printCodeViewTypeSection(SectionName, S);
|
|
|
|
}
|
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());
|
2016-01-14 03:32:35 +08:00
|
|
|
if (SectionName == ".debug$S")
|
|
|
|
printCodeViewSymbolSection(SectionName, S);
|
2015-12-17 02:28:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-04 01:11:11 +08:00
|
|
|
void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
|
|
|
|
while (Reader.bytesRemaining() > 0 &&
|
|
|
|
(!CVFileChecksumTable.valid() || !CVStringTable.valid())) {
|
2016-01-15 08:11:21 +08:00
|
|
|
// The section consists of a number of subsection in the following format:
|
|
|
|
// |SubSectionType|SubSectionSize|Contents...|
|
|
|
|
uint32_t SubType, SubSectionSize;
|
2019-08-13 20:07:41 +08:00
|
|
|
|
|
|
|
if (Error E = Reader.readInteger(SubType))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E = Reader.readInteger(SubSectionSize))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-05-04 01:11:11 +08:00
|
|
|
|
|
|
|
StringRef Contents;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = Reader.readFixedString(Contents, SubSectionSize))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-05-04 01:11:11 +08:00
|
|
|
|
2017-05-31 01:13:33 +08:00
|
|
|
BinaryStreamRef ST(Contents, support::little);
|
2017-05-31 00:36:15 +08:00
|
|
|
switch (DebugSubsectionKind(SubType)) {
|
2017-05-31 01:13:33 +08:00
|
|
|
case DebugSubsectionKind::FileChecksums:
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = CVFileChecksumTable.initialize(ST))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2016-01-15 08:11:21 +08:00
|
|
|
break;
|
2017-05-31 01:13:33 +08:00
|
|
|
case DebugSubsectionKind::StringTable:
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = CVStringTable.initialize(ST))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-05-31 01:13:33 +08:00
|
|
|
break;
|
2016-01-15 08:11:21 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-05-04 01:11:11 +08:00
|
|
|
|
2016-05-29 04:04:48 +08:00
|
|
|
uint32_t PaddedSize = alignTo(SubSectionSize, 4);
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = Reader.skip(PaddedSize - SubSectionSize))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2016-01-15 08:11:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
|
|
|
|
const SectionRef &Section) {
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef SectionContents =
|
|
|
|
unwrapOrError(Obj->getFileName(), Section.getContents());
|
2016-01-14 03:32:35 +08:00
|
|
|
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");
|
[llvm-readelf] Make llvm-readelf more compatible with GNU readelf.
Summary:
This change adds a bunch of options that GNU readelf supports. There is one breaking change when invoked as `llvm-readobj`, and three breaking changes when invoked as `llvm-readelf`:
- Add --all (implies --file-header, --program-headers, etc.)
- [Breaking] -a is --all instead of --arm-attributes
- Add --file-header as an alias for --file-headers
- Replace --sections with --sections-headers, keeping --sections as an alias for it
- Add --relocs as an alias for --relocations
- Add --dynamic as an alias for --dynamic-table
- Add --segments as an alias for --program-headers
- Add --section-groups as an alias for --elf-section-groups
- Add --dyn-syms as an alias for --dyn-symbols
- Add --syms as an alias for --symbols
- Add --histogram as an alias for --elf-hash-histogram
- [Breaking] When invoked as `llvm-readelf`, -s is --symbols instead of --sections
- [Breaking] When invoked as `llvm-readelf`, -t is no longer an alias for --symbols
Reviewers: MaskRay, phosek, mcgrathr, jhenderson
Reviewed By: MaskRay, jhenderson
Subscribers: sbc100, aheejin, edd, jhenderson, silvas, echristo, compnerd, kristina, javed.absar, kristof.beyls, llvm-commits, Bigcheese
Differential Revision: https://reviews.llvm.org/D54124
llvm-svn: 346685
2018-11-13 02:02:38 +08:00
|
|
|
// Print the section to allow correlation with printSectionHeaders.
|
2016-01-14 03:32:35 +08:00
|
|
|
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
|
|
|
|
|
|
|
|
uint32_t Magic;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = consume(Data, Magic))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
W.printHex("Magic", Magic);
|
|
|
|
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader FSReader(Data, support::little);
|
2017-05-04 01:11:11 +08:00
|
|
|
initializeFileAndStringTables(FSReader);
|
2016-01-15 08:11:21 +08:00
|
|
|
|
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;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = consume(Data, SubType))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E = consume(Data, SubSectionSize))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
|
|
|
|
ListScope S(W, "Subsection");
|
2019-06-19 03:41:25 +08:00
|
|
|
// Dump the subsection as normal even if the ignore bit is set.
|
|
|
|
if (SubType & SubsectionIgnoreFlag) {
|
|
|
|
W.printHex("IgnoredSubsectionKind", SubType);
|
|
|
|
SubType &= ~SubsectionIgnoreFlag;
|
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
|
|
|
|
W.printHex("SubSectionSize", SubSectionSize);
|
|
|
|
|
|
|
|
// Get the contents of the subsection.
|
|
|
|
if (SubSectionSize > Data.size())
|
2019-08-22 16:56:24 +08:00
|
|
|
return reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
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())
|
2019-08-22 16:56:24 +08:00
|
|
|
return reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
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-05-31 00:36:15 +08:00
|
|
|
switch (DebugSubsectionKind(SubType)) {
|
|
|
|
case DebugSubsectionKind::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-05-31 00:36:15 +08:00
|
|
|
case DebugSubsectionKind::InlineeLines:
|
2016-01-15 03:20:17 +08:00
|
|
|
printCodeViewInlineeLines(Contents);
|
|
|
|
break;
|
|
|
|
|
2017-05-31 00:36:15 +08:00
|
|
|
case DebugSubsectionKind::FileChecksums:
|
2016-01-16 02:06:25 +08:00
|
|
|
printCodeViewFileChecksums(Contents);
|
|
|
|
break;
|
|
|
|
|
2017-05-31 00:36:15 +08:00
|
|
|
case DebugSubsectionKind::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.
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-12-19 19:37:14 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef LinkageName;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = resolveSymbolName(Obj->getCOFFSection(Section),
|
|
|
|
SectionOffset, LinkageName))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
W.printString("LinkageName", LinkageName);
|
|
|
|
if (FunctionLineTables.count(LinkageName) != 0) {
|
|
|
|
// Saw debug info for this function already?
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2013-12-19 19:37:14 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
FunctionLineTables[LinkageName] = Contents;
|
|
|
|
FunctionNames.push_back(LinkageName);
|
|
|
|
break;
|
|
|
|
}
|
2017-05-31 00:36:15 +08:00
|
|
|
case DebugSubsectionKind::FrameData: {
|
2016-01-16 06:09:13 +08:00
|
|
|
// First four bytes is a relocation against the function.
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader SR(Contents, llvm::support::little);
|
2017-05-31 01:13:33 +08:00
|
|
|
|
|
|
|
DebugFrameDataSubsectionRef FrameData;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = FrameData.initialize(SR))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-05-31 01:13:33 +08:00
|
|
|
|
2016-01-14 03:32:35 +08:00
|
|
|
StringRef LinkageName;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC =
|
|
|
|
resolveSymbolName(Obj->getCOFFSection(Section), SectionContents,
|
|
|
|
FrameData.getRelocPtr(), LinkageName))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
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.
|
2017-05-31 01:13:33 +08:00
|
|
|
for (const auto &FD : FrameData) {
|
2019-08-09 19:03:21 +08:00
|
|
|
StringRef FrameFunc = unwrapOrError(
|
|
|
|
Obj->getFileName(), CVStringTable.getString(FD.FrameFunc));
|
2016-05-29 03:45:49 +08:00
|
|
|
|
2016-01-16 06:09:13 +08:00
|
|
|
DictScope S(W, "FrameData");
|
2017-05-31 01:13:33 +08:00
|
|
|
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);
|
|
|
|
W.printHex("PrologSize", FD.PrologSize);
|
|
|
|
W.printHex("SavedRegsSize", FD.SavedRegsSize);
|
|
|
|
W.printFlags("Flags", FD.Flags, makeArrayRef(FrameDataFlags));
|
2018-09-08 02:48:27 +08:00
|
|
|
|
|
|
|
// The FrameFunc string is a small RPN program. It can be broken up into
|
|
|
|
// statements that end in the '=' operator, which assigns the value on
|
|
|
|
// the top of the stack to the previously pushed variable. Variables can
|
|
|
|
// be temporary values ($T0) or physical registers ($esp). Print each
|
|
|
|
// assignment on its own line to make these programs easier to read.
|
|
|
|
{
|
|
|
|
ListScope FFS(W, "FrameFunc");
|
|
|
|
while (!FrameFunc.empty()) {
|
|
|
|
size_t EqOrEnd = FrameFunc.find('=');
|
|
|
|
if (EqOrEnd == StringRef::npos)
|
|
|
|
EqOrEnd = FrameFunc.size();
|
|
|
|
else
|
|
|
|
++EqOrEnd;
|
|
|
|
StringRef Stmt = FrameFunc.substr(0, EqOrEnd);
|
|
|
|
W.printString(Stmt);
|
|
|
|
FrameFunc = FrameFunc.drop_front(EqOrEnd).trim();
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader Reader(FunctionLineTables[Name], support::little);
|
2017-04-29 07:41:36 +08:00
|
|
|
|
2017-05-31 00:36:15 +08:00
|
|
|
DebugLinesSubsectionRef LineInfo;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = LineInfo.initialize(Reader))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-04-29 07:41:36 +08:00
|
|
|
|
|
|
|
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) {
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2013-12-19 19:37:14 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-04-29 07:41:36 +08:00
|
|
|
|
2020-01-29 03:23:46 +08:00
|
|
|
std::string PC = std::string(formatv("+{0:X}", uint32_t(Line.Offset)));
|
2017-04-29 07:41:36 +08:00
|
|
|
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());
|
2019-08-15 23:54:37 +08:00
|
|
|
auto CODD = std::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
2016-05-24 07:41:13 +08:00
|
|
|
SectionContents);
|
2017-06-02 05:52:41 +08:00
|
|
|
CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD),
|
2018-09-12 06:00:50 +08:00
|
|
|
CompilationCPUType, opts::CodeViewSubsectionBytes);
|
2016-05-28 13:21:57 +08:00
|
|
|
CVSymbolArray Symbols;
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader Reader(BinaryData, llvm::support::little);
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (Error E = Reader.readArray(Symbols, Reader.getLength())) {
|
2016-05-28 13:21:57 +08:00
|
|
|
W.flush();
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2016-05-28 13:21:57 +08:00
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = CVSD.dump(Symbols)) {
|
2016-01-16 06:09:13 +08:00
|
|
|
W.flush();
|
2019-08-13 20:07:41 +08:00
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
}
|
2018-09-12 06:00:50 +08:00
|
|
|
CompilationCPUType = CVSD.getCompilationCPUType();
|
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-05-31 01:13:33 +08:00
|
|
|
BinaryStreamRef Stream(Subsection, llvm::support::little);
|
2017-05-31 00:36:15 +08:00
|
|
|
DebugChecksumsSubsectionRef Checksums;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = Checksums.initialize(Stream))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-04-28 00:12:16 +08:00
|
|
|
|
|
|
|
for (auto &FC : Checksums) {
|
2016-01-16 02:06:25 +08:00
|
|
|
DictScope S(W, "FileChecksum");
|
2017-04-28 00:12:16 +08:00
|
|
|
|
2019-08-09 19:03:21 +08:00
|
|
|
StringRef Filename = unwrapOrError(
|
|
|
|
Obj->getFileName(), CVStringTable.getString(FC.FileNameOffset));
|
2017-04-28 00:12:16 +08:00
|
|
|
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) {
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader SR(Subsection, llvm::support::little);
|
2017-05-31 00:36:15 +08:00
|
|
|
DebugInlineeLinesSubsectionRef Lines;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = Lines.initialize(SR))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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.
|
2017-05-04 01:11:11 +08:00
|
|
|
if (!CVFileChecksumTable.valid() || !CVStringTable.valid())
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-15 08:11:21 +08:00
|
|
|
|
2017-05-31 01:13:33 +08:00
|
|
|
auto Iter = CVFileChecksumTable.getArray().at(FileOffset);
|
2016-01-15 08:11:21 +08:00
|
|
|
|
2017-05-04 01:11:11 +08:00
|
|
|
// Check if the file checksum table offset is valid.
|
|
|
|
if (Iter == CVFileChecksumTable.end())
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-15 08:11:21 +08:00
|
|
|
|
2019-08-09 19:03:21 +08:00
|
|
|
return unwrapOrError(Obj->getFileName(),
|
|
|
|
CVStringTable.getString(Iter->FileNameOffset));
|
2016-01-15 08:11:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
|
|
|
|
W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
|
|
|
|
}
|
|
|
|
|
2017-12-01 02:39:50 +08:00
|
|
|
void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
|
2019-02-07 23:24:18 +08:00
|
|
|
MergingTypeTableBuilder &CVTypes,
|
|
|
|
GlobalTypeTableBuilder &GlobalCVIDs,
|
|
|
|
GlobalTypeTableBuilder &GlobalCVTypes,
|
|
|
|
bool GHash) {
|
2016-05-14 08:02:53 +08:00
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());
|
2016-05-14 08:02:53 +08:00
|
|
|
if (SectionName == ".debug$T") {
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef Data = unwrapOrError(Obj->getFileName(), S.getContents());
|
2016-05-29 03:17:48 +08:00
|
|
|
uint32_t Magic;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = consume(Data, Magic))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
|
2016-05-14 08:02:53 +08:00
|
|
|
if (Magic != 4)
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
|
2016-05-28 13:21:57 +08:00
|
|
|
CVTypeArray Types;
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-18 04:23:31 +08:00
|
|
|
BinaryStreamReader Reader(Data, llvm::support::little);
|
2016-05-28 13:21:57 +08:00
|
|
|
if (auto EC = Reader.readArray(Types, Reader.getLength())) {
|
|
|
|
consumeError(std::move(EC));
|
|
|
|
W.flush();
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-05-28 13:21:57 +08:00
|
|
|
}
|
2017-05-19 07:04:08 +08:00
|
|
|
SmallVector<TypeIndex, 128> SourceToDest;
|
2019-01-07 21:53:16 +08:00
|
|
|
Optional<uint32_t> PCHSignature;
|
2019-02-07 23:24:18 +08:00
|
|
|
if (GHash) {
|
|
|
|
std::vector<GloballyHashedType> Hashes =
|
|
|
|
GloballyHashedType::hashTypes(Types);
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E =
|
2019-04-26 19:44:10 +08:00
|
|
|
mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,
|
|
|
|
Types, Hashes, PCHSignature))
|
2019-08-13 20:07:41 +08:00
|
|
|
return reportError(std::move(E), Obj->getFileName());
|
2019-02-07 23:24:18 +08:00
|
|
|
} else {
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
|
2019-02-07 23:24:18 +08:00
|
|
|
PCHSignature))
|
2019-08-13 20:07:41 +08:00
|
|
|
return reportError(std::move(E), Obj->getFileName());
|
2019-02-07 23:24:18 +08:00
|
|
|
}
|
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
|
|
|
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef Data = unwrapOrError(Obj->getFileName(), Section.getContents());
|
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;
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = consume(Data, Magic))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
|
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)
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2016-01-14 03:32:35 +08:00
|
|
|
|
2017-06-19 04:52:45 +08:00
|
|
|
Types.reset(Data, 100);
|
2017-05-20 03:26:58 +08:00
|
|
|
|
|
|
|
TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error E = codeview::visitTypeStream(Types, TDV))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
|
2017-05-20 03:26:58 +08:00
|
|
|
W.flush();
|
2016-05-05 03:39:28 +08:00
|
|
|
}
|
2016-01-14 03:32:35 +08:00
|
|
|
|
[llvm-readelf] Make llvm-readelf more compatible with GNU readelf.
Summary:
This change adds a bunch of options that GNU readelf supports. There is one breaking change when invoked as `llvm-readobj`, and three breaking changes when invoked as `llvm-readelf`:
- Add --all (implies --file-header, --program-headers, etc.)
- [Breaking] -a is --all instead of --arm-attributes
- Add --file-header as an alias for --file-headers
- Replace --sections with --sections-headers, keeping --sections as an alias for it
- Add --relocs as an alias for --relocations
- Add --dynamic as an alias for --dynamic-table
- Add --segments as an alias for --program-headers
- Add --section-groups as an alias for --elf-section-groups
- Add --dyn-syms as an alias for --dyn-symbols
- Add --syms as an alias for --symbols
- Add --histogram as an alias for --elf-hash-histogram
- [Breaking] When invoked as `llvm-readelf`, -s is --symbols instead of --sections
- [Breaking] When invoked as `llvm-readelf`, -t is no longer an alias for --symbols
Reviewers: MaskRay, phosek, mcgrathr, jhenderson
Reviewed By: MaskRay, jhenderson
Subscribers: sbc100, aheejin, edd, jhenderson, silvas, echristo, compnerd, kristina, javed.absar, kristof.beyls, llvm-commits, Bigcheese
Differential Revision: https://reviews.llvm.org/D54124
llvm-svn: 346685
2018-11-13 02:02:38 +08:00
|
|
|
void COFFDumper::printSectionHeaders() {
|
2013-04-04 02:31:38 +08:00
|
|
|
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
|
|
|
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName());
|
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)) {
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef Data = unwrapOrError(Obj->getFileName(), Sec.getContents());
|
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;
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());
|
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();
|
2019-01-03 16:08:23 +08:00
|
|
|
int64_t SymbolIndex = -1;
|
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();
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (!SymbolNameOrErr)
|
|
|
|
reportError(SymbolNameOrErr.takeError(), Obj->getFileName());
|
|
|
|
|
2015-07-03 04:55:21 +08:00
|
|
|
SymbolName = *SymbolNameOrErr;
|
2019-01-03 16:08:23 +08:00
|
|
|
SymbolIndex = Obj->getSymbolIndex(Obj->getCOFFSymbol(*Symbol));
|
2015-07-03 04:55:21 +08:00
|
|
|
}
|
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);
|
2019-01-03 16:08:23 +08:00
|
|
|
W.printNumber("SymbolIndex", SymbolIndex);
|
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)
|
2019-01-03 16:08:23 +08:00
|
|
|
<< " (" << SymbolIndex << ")"
|
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
|
|
|
|
2019-05-02 18:32:03 +08:00
|
|
|
static Expected<StringRef>
|
2014-11-17 19:17:17 +08:00
|
|
|
getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
|
|
|
|
const coff_section *Section) {
|
2019-05-02 18:32:03 +08:00
|
|
|
if (Section)
|
|
|
|
return Obj->getSectionName(Section);
|
2014-09-20 08:25:06 +08:00
|
|
|
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);
|
2020-05-09 01:41:05 +08:00
|
|
|
Expected<const coff_section *> SecOrErr =
|
|
|
|
Obj->getSection(Symbol.getSectionNumber());
|
|
|
|
if (!SecOrErr) {
|
|
|
|
W.startLine() << "Invalid section number: " << Symbol.getSectionNumber()
|
|
|
|
<< "\n";
|
2013-04-04 02:31:38 +08:00
|
|
|
W.flush();
|
2020-05-09 01:41:05 +08:00
|
|
|
consumeError(SecOrErr.takeError());
|
2013-04-04 02:31:38 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-05-09 01:41:05 +08:00
|
|
|
const coff_section *Section = *SecOrErr;
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
StringRef SymbolName;
|
2020-05-09 01:41:05 +08:00
|
|
|
if (Expected<StringRef> SymNameOrErr = Obj->getSymbolName(Symbol))
|
|
|
|
SymbolName = *SymNameOrErr;
|
2013-04-04 02:31:38 +08:00
|
|
|
|
2019-05-02 18:32:03 +08:00
|
|
|
StringRef SectionName;
|
2020-05-09 01:41:05 +08:00
|
|
|
if (Expected<StringRef> SecNameOrErr =
|
2019-05-02 18:32:03 +08:00
|
|
|
getSectionName(Obj, Symbol.getSectionNumber(), Section))
|
2020-05-09 01:41:05 +08:00
|
|
|
SectionName = *SecNameOrErr;
|
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;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
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;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
DictScope AS(W, "AuxWeakExternal");
|
2020-06-16 07:29:36 +08:00
|
|
|
W.printNumber("Linked", getSymbolName(Aux->TagIndex), Aux->TagIndex);
|
2013-04-04 02:31:38 +08:00
|
|
|
W.printEnum ("Search", Aux->Characteristics,
|
|
|
|
makeArrayRef(WeakExternalCharacteristics));
|
|
|
|
|
2014-09-10 20:51:52 +08:00
|
|
|
} else if (Symbol.isFileRecord()) {
|
|
|
|
const char *FileName;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, FileName))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
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;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
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) {
|
2020-05-09 01:41:05 +08:00
|
|
|
Expected<const coff_section *> Assoc = Obj->getSection(AuxNumber);
|
|
|
|
if (!Assoc)
|
|
|
|
reportError(Assoc.takeError(), Obj->getFileName());
|
|
|
|
Expected<StringRef> AssocName = getSectionName(Obj, AuxNumber, *Assoc);
|
|
|
|
if (!AssocName)
|
|
|
|
reportError(AssocName.takeError(), Obj->getFileName());
|
|
|
|
|
|
|
|
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;
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(EC), Obj->getFileName());
|
2013-04-04 02:31:38 +08:00
|
|
|
|
|
|
|
DictScope AS(W, "AuxCLRToken");
|
|
|
|
W.printNumber("AuxType", Aux->AuxType);
|
|
|
|
W.printNumber("Reserved", Aux->Reserved);
|
2020-06-16 07:29:36 +08:00
|
|
|
W.printNumber("SymbolTableIndex", getSymbolName(Aux->SymbolTableIndex),
|
|
|
|
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
|
|
|
}
|
2018-10-24 08:03:34 +08:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARM64:
|
2014-06-04 23:47:15 +08:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT: {
|
2018-10-24 08:03:34 +08:00
|
|
|
ARM::WinEH::Decoder Decoder(W, Obj->getMachine() ==
|
|
|
|
COFF::IMAGE_FILE_MACHINE_ARM64);
|
2019-05-02 18:32:03 +08:00
|
|
|
// TODO Propagate the error.
|
|
|
|
consumeError(Decoder.dumpProcedureData(*Obj));
|
2014-06-04 23:47:15 +08:00
|
|
|
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
|
|
|
|
2017-12-28 03:59:56 +08:00
|
|
|
void COFFDumper::printNeededLibraries() {
|
|
|
|
ListScope D(W, "NeededLibraries");
|
|
|
|
|
|
|
|
using LibsTy = std::vector<StringRef>;
|
|
|
|
LibsTy Libs;
|
|
|
|
|
|
|
|
for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
|
|
|
|
StringRef Name;
|
|
|
|
if (!DirRef.getName(Name))
|
|
|
|
Libs.push_back(Name);
|
|
|
|
}
|
|
|
|
|
2019-04-22 23:53:43 +08:00
|
|
|
llvm::stable_sort(Libs);
|
2017-12-28 03:59:56 +08:00
|
|
|
|
|
|
|
for (const auto &L : Libs) {
|
2019-06-13 04:16:22 +08:00
|
|
|
W.startLine() << L << "\n";
|
2017-12-28 03:59:56 +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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getSymbolName(Sym))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2014-10-03 08:41:58 +08:00
|
|
|
uint16_t Ordinal;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getOrdinal(Ordinal))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = S.getSymbolName(Sym))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
|
2014-11-13 11:22:54 +08:00
|
|
|
uint16_t Ordinal;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = S.getOrdinal(Ordinal))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2014-11-13 11:22:54 +08:00
|
|
|
W.printNumber("Symbol", Sym, Ordinal);
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
|
2014-11-13 11:22:54 +08:00
|
|
|
uint64_t Addr;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getImportAddress(Index++, Addr))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getName(Name))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2014-10-03 01:02:18 +08:00
|
|
|
W.printString("Name", Name);
|
2017-03-27 01:10:11 +08:00
|
|
|
uint32_t ILTAddr;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getImportLookupTableRVA(ILTAddr))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-03-27 01:10:11 +08:00
|
|
|
W.printHex("ImportLookupTableRVA", ILTAddr);
|
|
|
|
uint32_t IATAddr;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getImportAddressTableRVA(IATAddr))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2017-03-27 01:10:11 +08:00
|
|
|
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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getName(Name))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getDelayImportTable(Table))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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() {
|
2020-06-12 04:00:54 +08:00
|
|
|
for (const ExportDirectoryEntryRef &Exp : Obj->export_directories()) {
|
2015-01-04 05:35:09 +08:00
|
|
|
DictScope Export(W, "Export");
|
|
|
|
|
|
|
|
StringRef Name;
|
|
|
|
uint32_t Ordinal, RVA;
|
|
|
|
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = Exp.getSymbolName(Name))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E = Exp.getOrdinal(Ordinal))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E = Exp.getExportRVA(RVA))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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()) {
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());
|
2014-10-08 03:37:52 +08:00
|
|
|
if (Name != ".drectve")
|
|
|
|
continue;
|
|
|
|
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef Contents =
|
|
|
|
unwrapOrError(Obj->getFileName(), Section.getContents());
|
2014-10-08 03:37:52 +08:00
|
|
|
W.printString("Directive(s)", Contents);
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 08:18:07 +08:00
|
|
|
|
2017-07-26 18:14:55 +08:00
|
|
|
static std::string 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";
|
2017-07-26 18:14:55 +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;
|
2020-06-12 04:00:54 +08:00
|
|
|
if (Error E = I.getRVA(RVA))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
|
|
|
if (Error E = I.getType(Type))
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
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()) {
|
2019-08-14 19:10:11 +08:00
|
|
|
StringRef Name = unwrapOrError(Obj->getFileName(), S.getName());
|
2017-04-28 03:38:38 +08:00
|
|
|
if (!Name.startswith(".rsrc"))
|
|
|
|
continue;
|
|
|
|
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents());
|
2017-04-28 03:38:38 +08:00
|
|
|
|
|
|
|
if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 14:55:49 +08:00
|
|
|
ResourceSectionRef RSF;
|
|
|
|
Error E = RSF.load(Obj, S);
|
|
|
|
if (E)
|
|
|
|
reportError(std::move(E), Obj->getFileName());
|
2019-08-09 18:53:12 +08:00
|
|
|
auto &BaseTable = unwrapOrError(Obj->getFileName(), RSF.getBaseTable());
|
2017-06-13 08:16:32 +08:00
|
|
|
W.printNumber("Total Number of Resources",
|
|
|
|
countTotalTableEntries(RSF, BaseTable, "Type"));
|
|
|
|
W.printHex("Base Table Address",
|
|
|
|
Obj->getCOFFSection(S)->PointerToRawData);
|
|
|
|
W.startLine() << "\n";
|
2017-05-08 10:47:07 +08:00
|
|
|
printResourceDirectoryTable(RSF, BaseTable, "Type");
|
|
|
|
}
|
|
|
|
if (opts::SectionData)
|
|
|
|
W.printBinaryBlock(Name.str() + " Data", Ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-13 08:16:32 +08:00
|
|
|
uint32_t
|
|
|
|
COFFDumper::countTotalTableEntries(ResourceSectionRef RSF,
|
|
|
|
const coff_resource_dir_table &Table,
|
|
|
|
StringRef Level) {
|
|
|
|
uint32_t TotalEntries = 0;
|
|
|
|
for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
|
|
|
|
i++) {
|
2019-08-29 16:59:56 +08:00
|
|
|
auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i));
|
2017-06-13 08:16:32 +08:00
|
|
|
if (Entry.Offset.isSubDir()) {
|
|
|
|
StringRef NextLevel;
|
|
|
|
if (Level == "Name")
|
|
|
|
NextLevel = "Language";
|
|
|
|
else
|
|
|
|
NextLevel = "Name";
|
2019-08-09 18:53:12 +08:00
|
|
|
auto &NextTable =
|
|
|
|
unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry));
|
2017-06-13 08:16:32 +08:00
|
|
|
TotalEntries += countTotalTableEntries(RSF, NextTable, NextLevel);
|
|
|
|
} else {
|
|
|
|
TotalEntries += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TotalEntries;
|
|
|
|
}
|
|
|
|
|
2017-05-08 10:47:07 +08:00
|
|
|
void COFFDumper::printResourceDirectoryTable(
|
|
|
|
ResourceSectionRef RSF, const coff_resource_dir_table &Table,
|
|
|
|
StringRef Level) {
|
|
|
|
|
2017-06-13 08:16:32 +08:00
|
|
|
W.printNumber("Number of String Entries", Table.NumberOfNameEntries);
|
|
|
|
W.printNumber("Number of ID Entries", Table.NumberOfIDEntries);
|
2017-05-08 10:47:07 +08:00
|
|
|
|
|
|
|
// Iterate through level in resource directory tree.
|
|
|
|
for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
|
|
|
|
i++) {
|
2019-08-29 16:59:56 +08:00
|
|
|
auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i));
|
2017-05-08 10:47:07 +08:00
|
|
|
StringRef Name;
|
|
|
|
SmallString<20> IDStr;
|
|
|
|
raw_svector_ostream OS(IDStr);
|
|
|
|
if (i < Table.NumberOfNameEntries) {
|
2019-04-26 19:44:10 +08:00
|
|
|
ArrayRef<UTF16> RawEntryNameString =
|
2019-08-09 18:53:12 +08:00
|
|
|
unwrapOrError(Obj->getFileName(), RSF.getEntryNameString(Entry));
|
2017-05-10 03:35:45 +08:00
|
|
|
std::vector<UTF16> EndianCorrectedNameString;
|
|
|
|
if (llvm::sys::IsBigEndianHost) {
|
|
|
|
EndianCorrectedNameString.resize(RawEntryNameString.size() + 1);
|
|
|
|
std::copy(RawEntryNameString.begin(), RawEntryNameString.end(),
|
|
|
|
EndianCorrectedNameString.begin() + 1);
|
|
|
|
EndianCorrectedNameString[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
|
|
|
|
RawEntryNameString = makeArrayRef(EndianCorrectedNameString);
|
|
|
|
}
|
2017-05-08 10:47:42 +08:00
|
|
|
std::string EntryNameString;
|
|
|
|
if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, EntryNameString))
|
2019-08-22 16:56:24 +08:00
|
|
|
reportError(errorCodeToError(object_error::parse_failed),
|
|
|
|
Obj->getFileName());
|
2017-05-08 10:47:07 +08:00
|
|
|
OS << ": ";
|
2017-05-08 10:47:42 +08:00
|
|
|
OS << EntryNameString;
|
2017-05-08 10:47:07 +08:00
|
|
|
} else {
|
|
|
|
if (Level == "Type") {
|
2019-04-25 07:26:30 +08:00
|
|
|
OS << ": ";
|
|
|
|
printResourceTypeName(Entry.Identifier.ID, OS);
|
2017-05-08 10:47:07 +08:00
|
|
|
} else {
|
|
|
|
OS << ": (ID " << Entry.Identifier.ID << ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Name = StringRef(IDStr);
|
|
|
|
ListScope ResourceType(W, Level.str() + Name.str());
|
|
|
|
if (Entry.Offset.isSubDir()) {
|
2017-06-13 08:16:32 +08:00
|
|
|
W.printHex("Table Offset", Entry.Offset.value());
|
2017-05-08 10:47:07 +08:00
|
|
|
StringRef NextLevel;
|
|
|
|
if (Level == "Name")
|
|
|
|
NextLevel = "Language";
|
|
|
|
else
|
|
|
|
NextLevel = "Name";
|
2019-08-09 18:53:12 +08:00
|
|
|
auto &NextTable =
|
|
|
|
unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry));
|
2017-05-08 10:47:07 +08:00
|
|
|
printResourceDirectoryTable(RSF, NextTable, NextLevel);
|
|
|
|
} else {
|
2017-06-13 08:16:32 +08:00
|
|
|
W.printHex("Entry Offset", Entry.Offset.value());
|
|
|
|
char FormattedTime[20] = {};
|
|
|
|
time_t TDS = time_t(Table.TimeDateStamp);
|
|
|
|
strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
|
2017-05-08 10:47:07 +08:00
|
|
|
W.printHex("Time/Date Stamp", FormattedTime, Table.TimeDateStamp);
|
|
|
|
W.printNumber("Major Version", Table.MajorVersion);
|
|
|
|
W.printNumber("Minor Version", Table.MinorVersion);
|
2017-06-13 08:16:32 +08:00
|
|
|
W.printNumber("Characteristics", Table.Characteristics);
|
2019-08-29 17:00:14 +08:00
|
|
|
ListScope DataScope(W, "Data");
|
|
|
|
auto &DataEntry =
|
|
|
|
unwrapOrError(Obj->getFileName(), RSF.getEntryData(Entry));
|
|
|
|
W.printHex("DataRVA", DataEntry.DataRVA);
|
|
|
|
W.printNumber("DataSize", DataEntry.DataSize);
|
|
|
|
W.printNumber("Codepage", DataEntry.Codepage);
|
|
|
|
W.printNumber("Reserved", DataEntry.Reserved);
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 14:55:49 +08:00
|
|
|
StringRef Contents =
|
|
|
|
unwrapOrError(Obj->getFileName(), RSF.getContents(DataEntry));
|
|
|
|
W.printBinaryBlock("Data", Contents);
|
2017-05-08 06:47:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 07:56:53 +08:00
|
|
|
void COFFDumper::printStackMap() const {
|
2020-06-16 07:29:36 +08:00
|
|
|
SectionRef StackMapSection;
|
2015-06-27 07:56:53 +08:00
|
|
|
for (auto Sec : Obj->sections()) {
|
|
|
|
StringRef Name;
|
2019-08-14 19:10:11 +08:00
|
|
|
if (Expected<StringRef> NameOrErr = Sec.getName())
|
|
|
|
Name = *NameOrErr;
|
|
|
|
else
|
|
|
|
consumeError(NameOrErr.takeError());
|
|
|
|
|
2015-06-27 07:56:53 +08:00
|
|
|
if (Name == ".llvm_stackmaps") {
|
|
|
|
StackMapSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
if (StackMapSection == SectionRef())
|
2015-06-27 07:56:53 +08:00
|
|
|
return;
|
|
|
|
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef StackMapContents =
|
|
|
|
unwrapOrError(Obj->getFileName(), StackMapSection.getContents());
|
2019-04-07 11:58:42 +08:00
|
|
|
ArrayRef<uint8_t> StackMapContentsArray =
|
|
|
|
arrayRefFromStringRef(StackMapContents);
|
2015-06-27 07:56:53 +08:00
|
|
|
|
|
|
|
if (Obj->isLittleEndian())
|
|
|
|
prettyPrintStackMap(
|
2019-04-13 10:02:56 +08:00
|
|
|
W, StackMapParser<support::little>(StackMapContentsArray));
|
2015-06-27 07:56:53 +08:00
|
|
|
else
|
2019-04-13 10:23:08 +08:00
|
|
|
prettyPrintStackMap(
|
|
|
|
W, StackMapParser<support::big>(StackMapContentsArray));
|
2015-06-27 07:56:53 +08:00
|
|
|
}
|
2016-05-14 08:02:53 +08:00
|
|
|
|
2018-08-23 07:58:16 +08:00
|
|
|
void COFFDumper::printAddrsig() {
|
2020-06-16 07:29:36 +08:00
|
|
|
SectionRef AddrsigSection;
|
2018-08-23 07:58:16 +08:00
|
|
|
for (auto Sec : Obj->sections()) {
|
|
|
|
StringRef Name;
|
2019-08-14 19:10:11 +08:00
|
|
|
if (Expected<StringRef> NameOrErr = Sec.getName())
|
|
|
|
Name = *NameOrErr;
|
|
|
|
else
|
|
|
|
consumeError(NameOrErr.takeError());
|
|
|
|
|
2018-08-23 07:58:16 +08:00
|
|
|
if (Name == ".llvm_addrsig") {
|
|
|
|
AddrsigSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
if (AddrsigSection == SectionRef())
|
2018-08-23 07:58:16 +08:00
|
|
|
return;
|
|
|
|
|
2019-08-09 18:53:12 +08:00
|
|
|
StringRef AddrsigContents =
|
|
|
|
unwrapOrError(Obj->getFileName(), AddrsigSection.getContents());
|
2019-04-07 11:58:42 +08:00
|
|
|
ArrayRef<uint8_t> AddrsigContentsArray(AddrsigContents.bytes_begin(),
|
|
|
|
AddrsigContents.size());
|
2018-08-23 07:58:16 +08:00
|
|
|
|
|
|
|
ListScope L(W, "Addrsig");
|
2019-04-07 11:58:42 +08:00
|
|
|
const uint8_t *Cur = AddrsigContents.bytes_begin();
|
|
|
|
const uint8_t *End = AddrsigContents.bytes_end();
|
2018-08-23 07:58:16 +08:00
|
|
|
while (Cur != End) {
|
|
|
|
unsigned Size;
|
|
|
|
const char *Err;
|
|
|
|
uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err);
|
|
|
|
if (Err)
|
Recommit r369190 "[llvm-readobj/llvm-readelf] - Improve/cleanup the error reporting API."
Fix: Add a `consumeError` call removed by mistake to 'printStackSize',
this should fix the "Expected<T> must be checked before access or destruction." reported by following bot:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/9743/steps/stage%201%20check/logs/stdio
Original commit message:
Currently we have the following functions for error reporting:
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void reportError(Error Err, StringRef Input);
void reportWarning(Twine Msg);
void reportWarning(StringRef Input, Error Err);
void warn(llvm::Error Err);
void error(std::error_code EC);
Problems are: naming is inconsistent, arguments order is inconsistent,
some of the functions looks excessive.
After applying this patch we have:
void reportError(Error Err, StringRef Input);
void reportError(std::error_code EC, StringRef Input);
void reportWarning(Error Err, StringRef Input);
I'd be happy to remove reportError(std::error_code EC, StringRef Input) too, but it
is used by COFF heavily.
Test cases were updated, they show an improvement introduced.
Differential revision: https://reviews.llvm.org/D66286
llvm-svn: 369194
2019-08-18 00:07:18 +08:00
|
|
|
reportError(createError(Err), Obj->getFileName());
|
2018-08-23 07:58:16 +08:00
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
W.printNumber("Sym", getSymbolName(SymIndex), SymIndex);
|
|
|
|
Cur += Size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void COFFDumper::printCGProfile() {
|
|
|
|
SectionRef CGProfileSection;
|
|
|
|
for (SectionRef Sec : Obj->sections()) {
|
|
|
|
StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName());
|
|
|
|
if (Name == ".llvm.call-graph-profile") {
|
|
|
|
CGProfileSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-08-22 16:56:24 +08:00
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
if (CGProfileSection == SectionRef())
|
|
|
|
return;
|
2018-08-23 07:58:16 +08:00
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
StringRef CGProfileContents =
|
|
|
|
unwrapOrError(Obj->getFileName(), CGProfileSection.getContents());
|
|
|
|
BinaryStreamReader Reader(CGProfileContents, llvm::support::little);
|
|
|
|
|
|
|
|
ListScope L(W, "CGProfile");
|
|
|
|
while (!Reader.empty()) {
|
|
|
|
uint32_t FromIndex, ToIndex;
|
|
|
|
uint64_t Count;
|
|
|
|
if (Error Err = Reader.readInteger(FromIndex))
|
|
|
|
reportError(std::move(Err), Obj->getFileName());
|
|
|
|
if (Error Err = Reader.readInteger(ToIndex))
|
|
|
|
reportError(std::move(Err), Obj->getFileName());
|
|
|
|
if (Error Err = Reader.readInteger(Count))
|
|
|
|
reportError(std::move(Err), Obj->getFileName());
|
|
|
|
|
|
|
|
DictScope D(W, "CGProfileEntry");
|
|
|
|
W.printNumber("From", getSymbolName(FromIndex), FromIndex);
|
|
|
|
W.printNumber("To", getSymbolName(ToIndex), ToIndex);
|
|
|
|
W.printNumber("Weight", Count);
|
2018-08-23 07:58:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 07:29:36 +08:00
|
|
|
StringRef COFFDumper::getSymbolName(uint32_t Index) {
|
|
|
|
Expected<COFFSymbolRef> Sym = Obj->getSymbol(Index);
|
|
|
|
if (!Sym)
|
|
|
|
reportError(Sym.takeError(), Obj->getFileName());
|
|
|
|
|
|
|
|
Expected<StringRef> SymName = Obj->getSymbolName(*Sym);
|
|
|
|
if (!SymName)
|
|
|
|
reportError(SymName.takeError(), Obj->getFileName());
|
|
|
|
|
|
|
|
return *SymName;
|
|
|
|
}
|
|
|
|
|
2019-02-07 23:24:18 +08:00
|
|
|
void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
|
|
|
|
ArrayRef<ArrayRef<uint8_t>> IpiRecords,
|
|
|
|
ArrayRef<ArrayRef<uint8_t>> TpiRecords) {
|
|
|
|
TypeTableCollection TpiTypes(TpiRecords);
|
2017-03-25 01:26:38 +08:00
|
|
|
{
|
|
|
|
ListScope S(Writer, "MergedTypeStream");
|
2017-05-20 03:26:58 +08:00
|
|
|
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error Err = codeview::visitTypeStream(TpiTypes, TDV))
|
|
|
|
reportError(std::move(Err), "<?>");
|
2017-05-20 03:26:58 +08:00
|
|
|
Writer.flush();
|
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.
|
2019-02-07 23:24:18 +08:00
|
|
|
TypeTableCollection IpiTypes(IpiRecords);
|
2017-03-25 01:26:38 +08:00
|
|
|
{
|
|
|
|
ListScope S(Writer, "MergedIDStream");
|
2017-05-20 03:26:58 +08:00
|
|
|
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
|
|
|
|
TDV.setIpiTypes(IpiTypes);
|
2019-08-13 20:07:41 +08:00
|
|
|
if (Error Err = codeview::visitTypeStream(IpiTypes, TDV))
|
|
|
|
reportError(std::move(Err), "<?>");
|
2017-05-20 03:26:58 +08:00
|
|
|
Writer.flush();
|
2016-05-14 08:02:53 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-08 16:43:50 +08:00
|
|
|
|
|
|
|
void COFFDumper::printCOFFTLSDirectory() {
|
|
|
|
if (Obj->is64())
|
|
|
|
printCOFFTLSDirectory(Obj->getTLSDirectory64());
|
|
|
|
else
|
|
|
|
printCOFFTLSDirectory(Obj->getTLSDirectory32());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename IntTy>
|
|
|
|
void COFFDumper::printCOFFTLSDirectory(
|
|
|
|
const coff_tls_directory<IntTy> *TlsTable) {
|
|
|
|
DictScope D(W, "TLSDirectory");
|
|
|
|
if (!TlsTable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
W.printHex("StartAddressOfRawData", TlsTable->StartAddressOfRawData);
|
|
|
|
W.printHex("EndAddressOfRawData", TlsTable->EndAddressOfRawData);
|
|
|
|
W.printHex("AddressOfIndex", TlsTable->AddressOfIndex);
|
|
|
|
W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks);
|
|
|
|
W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill);
|
|
|
|
W.printFlags("Characteristics", TlsTable->Characteristics,
|
|
|
|
makeArrayRef(ImageSectionCharacteristics),
|
|
|
|
COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
|
|
|
|
}
|