//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file implements the COFF-specific dumper for llvm-readobj.
///
//===----------------------------------------------------------------------===//
#include "llvm-readobj.h"
#include "ObjDumper.h"
#include "Error.h"
#include "StreamWriter.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Win64EH.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstring>
#include <time.h>
using namespace llvm;
using namespace llvm::object;
using namespace llvm::Win64EH;
namespace {
class COFFDumper : public ObjDumper {
public:
COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
: ObjDumper(Writer)
, Obj(Obj) {
cacheRelocations();
}
virtual void printFileHeaders() LLVM_OVERRIDE;
virtual void printSections() LLVM_OVERRIDE;
virtual void printRelocations() LLVM_OVERRIDE;
virtual void printSymbols() LLVM_OVERRIDE;
virtual void printDynamicSymbols() LLVM_OVERRIDE;
virtual void printUnwindInfo() LLVM_OVERRIDE;
private:
void printSymbol(symbol_iterator SymI);
void printRelocation(section_iterator SecI, relocation_iterator RelI);
void printX64UnwindInfo();
void printRuntimeFunction(
const RuntimeFunction& RTF,
uint64_t OffsetInSection,
const std::vector<RelocationRef> &Rels);
void printUnwindInfo(
const Win64EH::UnwindInfo& UI,
uint64_t OffsetInSection,
const std::vector<RelocationRef> &Rels);
void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs);
void cacheRelocations();
error_code getSectionContents(
const std::vector<RelocationRef> &Rels,
uint64_t Offset,
ArrayRef<uint8_t> &Contents,
uint64_t &Addr);
error_code getSection(
const std::vector<RelocationRef> &Rels,
uint64_t Offset,
const coff_section **Section,
uint64_t *AddrPtr);
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
const llvm::object::COFFObjectFile *Obj;
RelocMapTy RelocMap;
std::vector<RelocationRef> EmptyRelocs;
};
} // namespace
namespace llvm {
error_code createCOFFDumper(const object::ObjectFile *Obj,
StreamWriter& Writer,
OwningPtr<ObjDumper> &Result) {
const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
if (!COFFObj)
return readobj_error::unsupported_obj_file_format;
Result.reset(new COFFDumper(COFFObj, Writer));
return readobj_error::success;
}
} // namespace llvm
// Returns the name of the unwind code.
static StringRef getUnwindCodeTypeName(uint8_t Code) {
switch(Code) {
default: llvm_unreachable("Invalid unwind code");
case UOP_PushNonVol: return "PUSH_NONVOL";
case UOP_AllocLarge: return "ALLOC_LARGE";
case UOP_AllocSmall: return "ALLOC_SMALL";
case UOP_SetFPReg: return "SET_FPREG";
case UOP_SaveNonVol: return "SAVE_NONVOL";
case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
case UOP_SaveXMM128: return "SAVE_XMM128";
case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
case UOP_PushMachFrame: return "PUSH_MACHFRAME";
}
}
// Returns the name of a referenced register.
static StringRef getUnwindRegisterName(uint8_t Reg) {
switch(Reg) {
default: llvm_unreachable("Invalid register");
case 0: return "RAX";
case 1: return "RCX";
case