[Object] Add tapi files to object

Summary:
The intention for this is to allow reading and printing symbols out from
llvm-nm. Tapi file, and Tapi universal follow a similiar format to
their respective MachO Object format.

The tests are dependent on llvm-nm processing tbd files which is why its in D66160

Reviewers: ributzka, steven_wu, lhames

Reviewed By: ributzka, lhames

Subscribers: mgorny, hiraditya, dexonsmith, llvm-commits

Tags: #llvm

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

llvm-svn: 369600
This commit is contained in:
Cyndy Ishida 2019-08-21 23:30:53 +00:00
parent 78e6507b0a
commit c20d1f90b5
8 changed files with 343 additions and 8 deletions

View File

@ -42,7 +42,9 @@ protected:
ID_Archive,
ID_MachOUniversalBinary,
ID_COFFImportFile,
ID_IR, // LLVM IR
ID_IR, // LLVM IR
ID_TapiUniversal, // Text-based Dynamic Library Stub file.
ID_TapiFile, // Text-based Dynamic Library Stub file.
ID_Minidump,
@ -101,16 +103,18 @@ public:
return TypeID > ID_StartObjects && TypeID < ID_EndObjects;
}
bool isSymbolic() const { return isIR() || isObject() || isCOFFImportFile(); }
bool isArchive() const {
return TypeID == ID_Archive;
bool isSymbolic() const {
return isIR() || isObject() || isCOFFImportFile() || isTapiFile();
}
bool isArchive() const { return TypeID == ID_Archive; }
bool isMachOUniversalBinary() const {
return TypeID == ID_MachOUniversalBinary;
}
bool isTapiUniversal() const { return TypeID == ID_TapiUniversal; }
bool isELF() const {
return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B;
}
@ -137,6 +141,8 @@ public:
bool isMinidump() const { return TypeID == ID_Minidump; }
bool isTapiFile() const { return TypeID == ID_TapiFile; }
bool isLittleEndian() const {
return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B ||
TypeID == ID_MachO32B || TypeID == ID_MachO64B);

View File

@ -0,0 +1,60 @@
//===- TapiFile.h - Text-based Dynamic Library Stub -------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file declares the TapiFile interface.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_OBJECT_TAPI_FILE_H
#define LLVM_OBJECT_TAPI_FILE_H
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TextAPI/MachO/InterfaceFile.h"
namespace llvm {
namespace object {
class TapiFile : public SymbolicFile {
public:
TapiFile(MemoryBufferRef Source, const MachO::InterfaceFile &interface,
MachO::Architecture Arch);
~TapiFile() override;
void moveSymbolNext(DataRefImpl &DRI) const override;
Error printSymbolName(raw_ostream &OS, DataRefImpl DRI) const override;
uint32_t getSymbolFlags(DataRefImpl DRI) const override;
basic_symbol_iterator symbol_begin() const override;
basic_symbol_iterator symbol_end() const override;
static bool classof(const Binary *v) { return v->isTapiFile(); }
private:
struct Symbol {
StringRef Prefix;
StringRef Name;
uint32_t Flags;
constexpr Symbol(StringRef Prefix, StringRef Name, uint32_t Flags)
: Prefix(Prefix), Name(Name), Flags(Flags) {}
};
std::vector<Symbol> Symbols;
};
} // end namespace object.
} // end namespace llvm.
#endif // LLVM_OBJECT_TAPI_FILE_H

View File

@ -0,0 +1,109 @@
//===-- TapiUniversal.h - Text-based Dynamic Library Stub -------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file declares the TapiUniversal interface.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_OBJECT_TAPI_UNIVERSAL_H
#define LLVM_OBJECT_TAPI_UNIVERSAL_H
#include "llvm/Object/Binary.h"
#include "llvm/Object/TapiFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TextAPI/MachO/Architecture.h"
#include "llvm/TextAPI/MachO/InterfaceFile.h"
namespace llvm {
namespace object {
class TapiUniversal : public Binary {
public:
class ObjectForArch {
const TapiUniversal *Parent;
int Index;
public:
ObjectForArch(const TapiUniversal *Parent, int Index)
: Parent(Parent), Index(Index) {}
ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); }
bool operator==(const ObjectForArch &Other) const {
return (Parent == Other.Parent) && (Index == Other.Index);
}
uint32_t getCPUType() const {
auto Result =
MachO::getCPUTypeFromArchitecture(Parent->Architectures[Index]);
return Result.first;
}
uint32_t getCPUSubType() const {
auto Result =
MachO::getCPUTypeFromArchitecture(Parent->Architectures[Index]);
return Result.second;
}
std::string getArchFlagName() const {
return MachO::getArchitectureName(Parent->Architectures[Index]);
}
Expected<std::unique_ptr<TapiFile>> getAsObjectFile() const;
};
class object_iterator {
ObjectForArch Obj;
public:
object_iterator(const ObjectForArch &Obj) : Obj(Obj) {}
const ObjectForArch *operator->() const { return &Obj; }
const ObjectForArch &operator*() const { return Obj; }
bool operator==(const object_iterator &Other) const {
return Obj == Other.Obj;
}
bool operator!=(const object_iterator &Other) const {
return !(*this == Other);
}
object_iterator &operator++() { // Preincrement
Obj = Obj.getNext();
return *this;
}
};
TapiUniversal(MemoryBufferRef Source, Error &Err);
static Expected<std::unique_ptr<TapiUniversal>>
create(MemoryBufferRef Source);
~TapiUniversal() override;
object_iterator begin_objects() const { return ObjectForArch(this, 0); }
object_iterator end_objects() const {
return ObjectForArch(this, Architectures.size());
}
iterator_range<object_iterator> objects() const {
return make_range(begin_objects(), end_objects());
}
uint32_t getNumberOfObjects() const { return Architectures.size(); }
// Cast methods.
static bool classof(const Binary *v) { return v->isTapiUniversal(); }
private:
std::unique_ptr<MachO::InterfaceFile> ParsedFile;
std::vector<MachO::Architecture> Architectures;
};
} // end namespace object.
} // end namespace llvm.
#endif // LLVM_OBJECT_TAPI_UNIVERSAL_H

View File

@ -18,6 +18,7 @@
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/Minidump.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/TapiUniversal.h"
#include "llvm/Object/WindowsResource.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
@ -87,8 +88,7 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
case file_magic::minidump:
return MinidumpFile::create(Buffer);
case file_magic::tapi_file:
// Placeholder until TAPI is supported for lib/Object
return errorCodeToError(object_error::invalid_file_type);
return TapiUniversal::create(Buffer);
}
llvm_unreachable("Unexpected Binary File Type");
}

View File

@ -21,6 +21,8 @@ add_llvm_library(LLVMObject
RelocationResolver.cpp
SymbolicFile.cpp
SymbolSize.cpp
TapiFile.cpp
TapiUniversal.cpp
WasmObjectFile.cpp
WindowsMachineFlag.cpp
WindowsResource.cpp

View File

@ -18,4 +18,4 @@
type = Library
name = Object
parent = Libraries
required_libraries = BitReader Core MC BinaryFormat MCParser Support
required_libraries = BitReader Core MC BinaryFormat MCParser Support TextAPI

View File

@ -0,0 +1,104 @@
//===- TapiFile.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the Text-based Dynamcic Library Stub format.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/TapiFile.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Error.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace llvm;
using namespace MachO;
using namespace object;
static constexpr StringLiteral ObjC1ClassNamePrefix = ".objc_class_name_";
static constexpr StringLiteral ObjC2ClassNamePrefix = "_OBJC_CLASS_$_";
static constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
static constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
static constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
static uint32_t getFlags(const Symbol *Sym) {
uint32_t Flags = BasicSymbolRef::SF_Global;
if (Sym->isUndefined())
Flags |= BasicSymbolRef::SF_Undefined;
else
Flags |= BasicSymbolRef::SF_Exported;
if (Sym->isWeakDefined() || Sym->isWeakReferenced())
Flags |= BasicSymbolRef::SF_Weak;
return Flags;
}
TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface,
Architecture Arch)
: SymbolicFile(ID_TapiFile, Source) {
for (const auto *Symbol : interface.symbols()) {
if (!Symbol->getArchitectures().has(Arch))
continue;
auto PlatformKind = interface.getPlatform();
switch (Symbol->getKind()) {
case SymbolKind::GlobalSymbol:
Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol));
break;
case SymbolKind::ObjectiveCClass:
if (PlatformKind == PlatformKind::macOS && Arch == AK_i386) {
Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(),
getFlags(Symbol));
} else {
Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(),
getFlags(Symbol));
Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(),
getFlags(Symbol));
}
break;
case SymbolKind::ObjectiveCClassEHType:
Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(),
getFlags(Symbol));
break;
case SymbolKind::ObjectiveCInstanceVariable:
Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(),
getFlags(Symbol));
break;
}
}
}
TapiFile::~TapiFile() = default;
void TapiFile::moveSymbolNext(DataRefImpl &DRI) const {
const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
DRI.p = reinterpret_cast<uintptr_t>(++Sym);
}
Error TapiFile::printSymbolName(raw_ostream &OS, DataRefImpl DRI) const {
const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
OS << Sym->Prefix << Sym->Name;
return Error::success();
}
uint32_t TapiFile::getSymbolFlags(DataRefImpl DRI) const {
const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
return Sym->Flags;
}
basic_symbol_iterator TapiFile::symbol_begin() const {
DataRefImpl DRI;
DRI.p = reinterpret_cast<uintptr_t>(&*Symbols.begin());
return BasicSymbolRef{DRI, this};
}
basic_symbol_iterator TapiFile::symbol_end() const {
DataRefImpl DRI;
DRI.p = reinterpret_cast<uintptr_t>(&*Symbols.end());
return BasicSymbolRef{DRI, this};
}

View File

@ -0,0 +1,54 @@
//===- TapiUniversal.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the Text-based Dynamic Library Stub format.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/TapiUniversal.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TextAPI/MachO/TextAPIReader.h"
using namespace llvm;
using namespace MachO;
using namespace object;
TapiUniversal::TapiUniversal(MemoryBufferRef Source, Error &Err)
: Binary(ID_TapiUniversal, Source) {
auto Result = TextAPIReader::get(Source);
ErrorAsOutParameter ErrAsOuParam(&Err);
if (!Result) {
Err = Result.takeError();
return;
}
ParsedFile = std::move(Result.get());
auto Archs = ParsedFile->getArchitectures();
for (auto Arch : Archs)
Architectures.emplace_back(Arch);
}
TapiUniversal::~TapiUniversal() = default;
Expected<std::unique_ptr<TapiFile>>
TapiUniversal::ObjectForArch::getAsObjectFile() const {
return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(),
*Parent->ParsedFile.get(),
Parent->Architectures[Index]));
}
Expected<std::unique_ptr<TapiUniversal>>
TapiUniversal::create(MemoryBufferRef Source) {
Error Err = Error::success();
std::unique_ptr<TapiUniversal> Ret(new TapiUniversal(Source, Err));
if (Err)
return std::move(Err);
return std::move(Ret);
}