[dsymutil] Implement support for universal mach-o object files.

This patch allows llvm-dsymutil to read universal (aka fat) macho object
files and archives. The patch touches nearly everything in the BinaryHolder,
but it is fairly mechinical: the methods that returned MemoryBufferRefs or
ObjectFiles now return a vector of those, and the high-level access function
takes a triple argument to select the architecture.

There is no support yet for handling fat executables and thus no support for
writing fat object files.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243096 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Frederic Riss
2015-07-24 06:41:11 +00:00
parent 1556296615
commit fa7f7bd017
13 changed files with 300 additions and 107 deletions

View File

@@ -0,0 +1,13 @@
# REQUIRES: object-emission
# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
---
triple: 'armv7-apple-darwin'
objects:
- filename: libfat-test.a(fat-test.o)
symbols:
- { sym: _armv7_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
...
# CHECK: libfat-test.a(fat-test.o): No object file for requested architecture

View File

@@ -0,0 +1,2 @@
if not 'X86' in config.root.targets:
config.unsupported = True

View File

@@ -0,0 +1,17 @@
/* Compile with:
clang -c -g -arch x86_64h -arch x86_64 -arch i386 fat-test.c
libtool -static -o libfat-test.a fat-test.o
To reduce the size of the fat .o:
lipo -thin i386 -o fat-test.i386.o fat-test.o
lipo -thin x86_64 -o fat-test.x86_64.o fat-test.o
lipo -thin x86_64h -o fat-test.x86_64h.o fat-test.o
lipo -create -arch x86_64h fat-test.x86_64h.o -arch x86_64 fat-test.x86_64.o -arch i386 fat-test.i386.o -o fat-test.o -segalign i386 8 -segalign x86_64 8 -segalign x86_64h 8
*/
#ifdef __x86_64h__
int x86_64h_var;
#elif defined(__x86_64__)
int x86_64_var;
#else
int i386_var;
#endif

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,16 @@
# REQUIRES: object-emission
# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
---
triple: 'i386-apple-darwin'
objects:
- filename: libfat-test.a(fat-test.o)
symbols:
- { sym: _i386_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
...
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NOT: {{DW_TAG|NULL}}
# CHECK: DW_AT_name{{.*}}"i386_var"

View File

@@ -0,0 +1,16 @@
# REQUIRES: object-emission
# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
---
triple: 'x86_64-apple-darwin'
objects:
- filename: fat-test.o
symbols:
- { sym: _x86_64_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
...
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NOT: {{DW_TAG|NULL}}
# CHECK: DW_AT_name{{.*}}"x86_64_var"

View File

@@ -0,0 +1,16 @@
# REQUIRES: object-emission
# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
---
triple: 'x86_64h-apple-darwin'
objects:
- filename: fat-test.o
symbols:
- { sym: _x86_64h_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
...
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NOT: {{DW_TAG|NULL}}
# CHECK: DW_AT_name{{.*}}"x86_64h_var"

View File

@@ -28,30 +28,44 @@ Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
return ThumbTriple.getArch() ? ThumbTriple : T; return ThumbTriple.getArch() ? ThumbTriple : T;
} }
static std::vector<MemoryBufferRef>
getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
object::MachOUniversalBinary &Fat) {
std::vector<MemoryBufferRef> Buffers;
StringRef FatData = Fat.getData();
for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
++It) {
StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
Buffers.emplace_back(ObjData, Filename);
}
return Buffers;
}
void BinaryHolder::changeBackingMemoryBuffer( void BinaryHolder::changeBackingMemoryBuffer(
std::unique_ptr<MemoryBuffer> &&Buf) { std::unique_ptr<MemoryBuffer> &&Buf) {
CurrentArchive.reset(); CurrentArchives.clear();
CurrentObjectFile.reset(); CurrentObjectFiles.clear();
CurrentFatBinary.reset();
CurrentMemoryBuffer = std::move(Buf); CurrentMemoryBuffer = std::move(Buf);
} }
ErrorOr<MemoryBufferRef> ErrorOr<std::vector<MemoryBufferRef>>
BinaryHolder::GetMemoryBufferForFile(StringRef Filename, BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
sys::TimeValue Timestamp) { sys::TimeValue Timestamp) {
if (Verbose) if (Verbose)
outs() << "trying to open '" << Filename << "'\n"; outs() << "trying to open '" << Filename << "'\n";
// Try that first as it doesn't involve any filesystem access. // Try that first as it doesn't involve any filesystem access.
if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp)) if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
return *ErrOrArchiveMember; return *ErrOrArchiveMembers;
// If the name ends with a closing paren, there is a huge chance // If the name ends with a closing paren, there is a huge chance
// it is an archive member specification. // it is an archive member specification.
if (Filename.endswith(")")) if (Filename.endswith(")"))
if (auto ErrOrArchiveMember = if (auto ErrOrArchiveMembers =
MapArchiveAndGetMemberBuffer(Filename, Timestamp)) MapArchiveAndGetMemberBuffers(Filename, Timestamp))
return *ErrOrArchiveMember; return *ErrOrArchiveMembers;
// Otherwise, just try opening a standard file. If this is an // Otherwise, just try opening a standard file. If this is an
// archive member specifiaction and any of the above didn't handle it // archive member specifiaction and any of the above didn't handle it
@@ -65,43 +79,64 @@ BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
changeBackingMemoryBuffer(std::move(*ErrOrFile)); changeBackingMemoryBuffer(std::move(*ErrOrFile));
if (Verbose) if (Verbose)
outs() << "\tloaded file.\n"; outs() << "\tloaded file.\n";
return CurrentMemoryBuffer->getMemBufferRef();
auto ErrOrFat = object::MachOUniversalBinary::create(
CurrentMemoryBuffer->getMemBufferRef());
if (ErrOrFat.getError()) {
// Not a fat binary must be a standard one. Return a one element vector.
return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
}
CurrentFatBinary = std::move(*ErrOrFat);
return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer,
*CurrentFatBinary);
} }
ErrorOr<MemoryBufferRef> ErrorOr<std::vector<MemoryBufferRef>>
BinaryHolder::GetArchiveMemberBuffer(StringRef Filename, BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
sys::TimeValue Timestamp) { sys::TimeValue Timestamp) {
if (!CurrentArchive) if (CurrentArchives.empty())
return make_error_code(errc::no_such_file_or_directory); return make_error_code(errc::no_such_file_or_directory);
StringRef CurArchiveName = CurrentArchive->getFileName(); StringRef CurArchiveName = CurrentArchives.front()->getFileName();
if (!Filename.startswith(Twine(CurArchiveName, "(").str())) if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
return make_error_code(errc::no_such_file_or_directory); return make_error_code(errc::no_such_file_or_directory);
// Remove the archive name and the parens around the archive member name. // Remove the archive name and the parens around the archive member name.
Filename = Filename.substr(CurArchiveName.size() + 1).drop_back(); Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
for (const auto &Child : CurrentArchive->children()) { std::vector<MemoryBufferRef> Buffers;
if (auto NameOrErr = Child.getName()) Buffers.reserve(CurrentArchives.size());
if (*NameOrErr == Filename) {
if (Timestamp != sys::TimeValue::PosixZeroTime() && for (const auto &CurrentArchive : CurrentArchives) {
Timestamp != Child.getLastModified()) { for (const auto &Child : CurrentArchive->children()) {
if (auto NameOrErr = Child.getName()) {
if (*NameOrErr == Filename) {
if (Timestamp != sys::TimeValue::PosixZeroTime() &&
Timestamp != Child.getLastModified()) {
if (Verbose)
outs() << "\tmember had timestamp mismatch.\n";
continue;
}
if (Verbose) if (Verbose)
outs() << "\tmember had timestamp mismatch.\n"; outs() << "\tfound member in current archive.\n";
continue; auto ErrOrMem = Child.getMemoryBufferRef();
if (auto Err = ErrOrMem.getError())
return Err;
Buffers.push_back(*ErrOrMem);
} }
if (Verbose)
outs() << "\tfound member in current archive.\n";
return Child.getMemoryBufferRef();
} }
}
} }
return make_error_code(errc::no_such_file_or_directory); if (Buffers.empty())
return make_error_code(errc::no_such_file_or_directory);
return Buffers;
} }
ErrorOr<MemoryBufferRef> ErrorOr<std::vector<MemoryBufferRef>>
BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename, BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
sys::TimeValue Timestamp) { sys::TimeValue Timestamp) {
StringRef ArchiveFilename = Filename.substr(0, Filename.find('(')); StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename); auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
@@ -112,29 +147,60 @@ BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
outs() << "\topened new archive '" << ArchiveFilename << "'\n"; outs() << "\topened new archive '" << ArchiveFilename << "'\n";
changeBackingMemoryBuffer(std::move(*ErrOrBuff)); changeBackingMemoryBuffer(std::move(*ErrOrBuff));
auto ErrOrArchive = std::vector<MemoryBufferRef> ArchiveBuffers;
object::Archive::create(CurrentMemoryBuffer->getMemBufferRef()); auto ErrOrFat = object::MachOUniversalBinary::create(
if (auto Err = ErrOrArchive.getError()) CurrentMemoryBuffer->getMemBufferRef());
return Err; if (ErrOrFat.getError()) {
// Not a fat binary must be a standard one.
ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
} else {
CurrentFatBinary = std::move(*ErrOrFat);
ArchiveBuffers = getMachOFatMemoryBuffers(
ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary);
}
CurrentArchive = std::move(*ErrOrArchive); for (auto MemRef : ArchiveBuffers) {
auto ErrOrArchive = object::Archive::create(MemRef);
return GetArchiveMemberBuffer(Filename, Timestamp); if (auto Err = ErrOrArchive.getError())
return Err;
CurrentArchives.push_back(std::move(*ErrOrArchive));
}
return GetArchiveMemberBuffers(Filename, Timestamp);
} }
ErrorOr<const object::ObjectFile &> ErrorOr<const object::ObjectFile &>
BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) { BinaryHolder::getObjfileForArch(const Triple &T) {
auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp); for (const auto &Obj : CurrentObjectFiles) {
if (auto Err = ErrOrMemBufferRef.getError()) if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
if (getTriple(*MachO).str() == T.str())
return *MachO;
} else if (Obj->getArch() == T.getArch())
return *Obj;
}
return make_error_code(object::object_error::arch_not_found);
}
ErrorOr<std::vector<const object::ObjectFile *>>
BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
if (auto Err = ErrOrMemBufferRefs.getError())
return Err; return Err;
auto ErrOrObjectFile = std::vector<const object::ObjectFile *> Objects;
object::ObjectFile::createObjectFile(*ErrOrMemBufferRef); Objects.reserve(ErrOrMemBufferRefs->size());
if (auto Err = ErrOrObjectFile.getError())
return Err;
CurrentObjectFile = std::move(*ErrOrObjectFile); CurrentObjectFiles.clear();
return *CurrentObjectFile; for (auto MemBuf : *ErrOrMemBufferRefs) {
auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
if (auto Err = ErrOrObjectFile.getError())
return Err;
Objects.push_back(ErrOrObjectFile->get());
CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
}
return std::move(Objects);
} }
} }
} }

View File

@@ -17,6 +17,7 @@
#include "llvm/ADT/Triple.h" #include "llvm/ADT/Triple.h"
#include "llvm/Object/Archive.h" #include "llvm/Object/Archive.h"
#include "llvm/Object/Error.h" #include "llvm/Object/Error.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h" #include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Errc.h" #include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorOr.h" #include "llvm/Support/ErrorOr.h"
@@ -37,77 +38,95 @@ namespace dsymutil {
/// meaning that a mapping request will invalidate the previous memory /// meaning that a mapping request will invalidate the previous memory
/// mapping. /// mapping.
class BinaryHolder { class BinaryHolder {
std::unique_ptr<object::Archive> CurrentArchive; std::vector<std::unique_ptr<object::Archive>> CurrentArchives;
std::unique_ptr<MemoryBuffer> CurrentMemoryBuffer; std::unique_ptr<MemoryBuffer> CurrentMemoryBuffer;
std::unique_ptr<object::ObjectFile> CurrentObjectFile; std::vector<std::unique_ptr<object::ObjectFile>> CurrentObjectFiles;
std::unique_ptr<object::MachOUniversalBinary> CurrentFatBinary;
bool Verbose; bool Verbose;
/// \brief Get the MemoryBufferRef for the file specification in \p /// Get the MemoryBufferRefs for the file specification in \p
/// Filename from the current archive. /// Filename from the current archive. Multiple buffers are returned
/// when there are multiple architectures available for the
/// requested file.
/// ///
/// This function performs no system calls, it just looks up a /// This function performs no system calls, it just looks up a
/// potential match for the given \p Filename in the currently /// potential match for the given \p Filename in the currently
/// mapped archive if there is one. /// mapped archive if there is one.
ErrorOr<MemoryBufferRef> GetArchiveMemberBuffer(StringRef Filename, ErrorOr<std::vector<MemoryBufferRef>>
sys::TimeValue Timestamp); GetArchiveMemberBuffers(StringRef Filename, sys::TimeValue Timestamp);
/// \brief Interpret Filename as an archive member specification, /// Interpret Filename as an archive member specification map the
/// map the corresponding archive to memory and return the /// corresponding archive to memory and return the MemoryBufferRefs
/// MemoryBufferRef corresponding to the described member. /// corresponding to the described member. Multiple buffers are
ErrorOr<MemoryBufferRef> /// returned when there are multiple architectures available for the
MapArchiveAndGetMemberBuffer(StringRef Filename, sys::TimeValue Timestamp); /// requested file.
ErrorOr<std::vector<MemoryBufferRef>>
MapArchiveAndGetMemberBuffers(StringRef Filename, sys::TimeValue Timestamp);
/// \brief Return the MemoryBufferRef that holds the memory /// Return the MemoryBufferRef that holds the memory mapping for the
/// mapping for the given \p Filename. This function will try to /// given \p Filename. This function will try to parse archive
/// parse archive member specifications of the form /// member specifications of the form /path/to/archive.a(member.o).
/// /path/to/archive.a(member.o).
/// ///
/// The returned MemoryBufferRef points to a buffer owned by this /// The returned MemoryBufferRefs points to a buffer owned by this
/// object. The buffer is valid until the next call to /// object. The buffer is valid until the next call to
/// GetMemoryBufferForFile() on this object. /// GetMemoryBufferForFile() on this object.
ErrorOr<MemoryBufferRef> GetMemoryBufferForFile(StringRef Filename, /// Multiple buffers are returned when there are multiple
sys::TimeValue Timestamp); /// architectures available for the requested file.
ErrorOr<std::vector<MemoryBufferRef>>
GetMemoryBuffersForFile(StringRef Filename, sys::TimeValue Timestamp);
void changeBackingMemoryBuffer(std::unique_ptr<MemoryBuffer> &&MemBuf); void changeBackingMemoryBuffer(std::unique_ptr<MemoryBuffer> &&MemBuf);
ErrorOr<const object::ObjectFile &> getObjfileForArch(const Triple &T);
public: public:
BinaryHolder(bool Verbose) : Verbose(Verbose) {} BinaryHolder(bool Verbose) : Verbose(Verbose) {}
/// \brief Get the ObjectFile designated by the \p Filename. This /// Get the ObjectFiles designated by the \p Filename. This
/// might be an archive member specification of the form /// might be an archive member specification of the form
/// /path/to/archive.a(member.o). /// /path/to/archive.a(member.o).
/// ///
/// Calling this function invalidates the previous mapping owned by /// Calling this function invalidates the previous mapping owned by
/// the BinaryHolder. /// the BinaryHolder. Multiple buffers are returned when there are
ErrorOr<const object::ObjectFile &> /// multiple architectures available for the requested file.
GetObjectFile(StringRef Filename, ErrorOr<std::vector<const object::ObjectFile *>>
sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()); GetObjectFiles(StringRef Filename,
sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime());
/// \brief Wraps GetObjectFile() to return a derived ObjectFile type. /// Wraps GetObjectFiles() to return a derived ObjectFile type.
template <typename ObjectFileType> template <typename ObjectFileType>
ErrorOr<const ObjectFileType &> ErrorOr<std::vector<const ObjectFileType *>>
GetFileAs(StringRef Filename, GetFilesAs(StringRef Filename,
sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) { sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) {
auto ErrOrObjFile = GetObjectFile(Filename); auto ErrOrObjFile = GetObjectFiles(Filename, Timestamp);
if (auto Err = ErrOrObjFile.getError()) if (auto Err = ErrOrObjFile.getError())
return Err; return Err;
if (const auto *Derived = dyn_cast<ObjectFileType>(CurrentObjectFile.get()))
return *Derived; std::vector<const ObjectFileType *> Objects;
return make_error_code(object::object_error::invalid_file_type); Objects.reserve((*ErrOrObjFile).size());
for (const auto &Obj : *ErrOrObjFile) {
const auto *Derived = dyn_cast<ObjectFileType>(Obj);
if (!Derived)
return make_error_code(object::object_error::invalid_file_type);
Objects.push_back(Derived);
}
return std::move(Objects);
} }
/// \brief Access the currently owned ObjectFile. As successfull /// Access the currently owned ObjectFile with architecture \p T. As
/// call to GetObjectFile() or GetFileAs() must have been performed /// successfull call to GetObjectFiles() or GetFilesAs() must have
/// before calling this. /// been performed before calling this.
const object::ObjectFile &Get() { ErrorOr<const object::ObjectFile &> Get(const Triple &T) {
assert(CurrentObjectFile); return getObjfileForArch(T);
return *CurrentObjectFile;
} }
/// \brief Access to a derived version of the currently owned /// Access to a derived version of the currently owned
/// ObjectFile. The conversion must be known to be valid. /// ObjectFile. The conversion must be known to be valid.
template <typename ObjectFileType> const ObjectFileType &GetAs() { template <typename ObjectFileType>
return cast<ObjectFileType>(*CurrentObjectFile); ErrorOr<const ObjectFileType &> GetAs(const Triple &T) {
auto ErrOrObj = Get(T);
if (auto Err = ErrOrObj.getError())
return Err;
return cast<ObjectFileType>(*ErrOrObj);
} }
static Triple getTriple(const object::MachOObjectFile &Obj); static Triple getTriple(const object::MachOObjectFile &Obj);

View File

@@ -178,9 +178,9 @@ SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
dsymutil::DebugMap &DM) { dsymutil::DebugMap &DM) {
io.mapRequired("triple", DM.BinaryTriple); io.mapRequired("triple", DM.BinaryTriple);
io.mapOptional("objects", DM.Objects);
if (void *Ctxt = io.getContext()) if (void *Ctxt = io.getContext())
reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
io.mapOptional("objects", DM.Objects);
} }
void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
@@ -188,9 +188,9 @@ void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
if (!DM) if (!DM)
DM.reset(new DebugMap()); DM.reset(new DebugMap());
io.mapRequired("triple", DM->BinaryTriple); io.mapRequired("triple", DM->BinaryTriple);
io.mapOptional("objects", DM->Objects);
if (void *Ctxt = io.getContext()) if (void *Ctxt = io.getContext())
reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
io.mapOptional("objects", DM->Objects);
} }
MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
@@ -210,11 +210,11 @@ MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
StringMap<uint64_t> SymbolAddresses; StringMap<uint64_t> SymbolAddresses;
sys::path::append(Path, Filename); sys::path::append(Path, Filename);
auto ErrOrObjectFile = BinHolder.GetObjectFile(Path); auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path);
if (auto EC = ErrOrObjectFile.getError()) { if (auto EC = ErrOrObjectFiles.getError()) {
llvm::errs() << "warning: Unable to open " << Path << " " << EC.message() llvm::errs() << "warning: Unable to open " << Path << " " << EC.message()
<< '\n'; << '\n';
} else { } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) {
// Rewrite the object file symbol addresses in the debug map. The // Rewrite the object file symbol addresses in the debug map. The
// YAML input is mainly used to test llvm-dsymutil without // YAML input is mainly used to test llvm-dsymutil without
// requiring binaries checked-in. If we generate the object files // requiring binaries checked-in. If we generate the object files

View File

@@ -1410,6 +1410,11 @@ private:
const DWARFDebugInfoEntryMinimal *DIE = nullptr) const; const DWARFDebugInfoEntryMinimal *DIE = nullptr) const;
bool createStreamer(Triple TheTriple, StringRef OutputFilename); bool createStreamer(Triple TheTriple, StringRef OutputFilename);
/// \brief Attempt to load a debug object from disk.
ErrorOr<const object::ObjectFile &> loadObject(BinaryHolder &BinaryHolder,
DebugMapObject &Obj,
const DebugMap &Map);
/// @} /// @}
private: private:
@@ -3008,6 +3013,19 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO,
} }
} }
ErrorOr<const object::ObjectFile &>
DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
const DebugMap &Map) {
auto ErrOrObjs =
BinaryHolder.GetObjectFiles(Obj.getObjectFilename(), Obj.getTimestamp());
if (std::error_code EC = ErrOrObjs.getError())
reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
auto ErrOrObj = BinaryHolder.Get(Map.getTriple());
if (std::error_code EC = ErrOrObj.getError())
reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
return ErrOrObj;
}
bool DwarfLinker::link(const DebugMap &Map) { bool DwarfLinker::link(const DebugMap &Map) {
if (Map.begin() == Map.end()) { if (Map.begin() == Map.end()) {
@@ -3027,12 +3045,9 @@ bool DwarfLinker::link(const DebugMap &Map) {
if (Options.Verbose) if (Options.Verbose)
outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
auto ErrOrObj = auto ErrOrObj = loadObject(BinHolder, *Obj, Map);
BinHolder.GetObjectFile(Obj->getObjectFilename(), Obj->getTimestamp()); if (!ErrOrObj)
if (std::error_code EC = ErrOrObj.getError()) {
reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message());
continue; continue;
}
// Look for relocations that correspond to debug map entries. // Look for relocations that correspond to debug map entries.
if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {

View File

@@ -58,8 +58,8 @@ private:
void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp); void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp);
void resetParserState(); void resetParserState();
uint64_t getMainBinarySymbolAddress(StringRef Name); uint64_t getMainBinarySymbolAddress(StringRef Name);
void loadMainBinarySymbols(); void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
void loadCurrentObjectFileSymbols(); void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
uint8_t SectionIndex, uint16_t Flags, uint8_t SectionIndex, uint16_t Flags,
uint64_t Value); uint64_t Value);
@@ -92,27 +92,38 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename,
sys::path::append(Path, Filename); sys::path::append(Path, Filename);
auto MachOOrError = auto MachOOrError =
CurrentObjectHolder.GetFileAs<MachOObjectFile>(Path, Timestamp); CurrentObjectHolder.GetFilesAs<MachOObjectFile>(Path, Timestamp);
if (auto Error = MachOOrError.getError()) { if (auto Error = MachOOrError.getError()) {
Warning(Twine("cannot open debug object \"") + Path.str() + "\": " + Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
Error.message() + "\n"); Error.message() + "\n");
return; return;
} }
loadCurrentObjectFileSymbols(); auto ErrOrAchObj =
CurrentObjectHolder.GetAs<MachOObjectFile>(Result->getTriple());
if (auto Err = ErrOrAchObj.getError()) {
return Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
Err.message() + "\n");
}
CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp); CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp);
loadCurrentObjectFileSymbols(*ErrOrAchObj);
} }
/// This main parsing routine tries to open the main binary and if /// This main parsing routine tries to open the main binary and if
/// successful iterates over the STAB entries. The real parsing is /// successful iterates over the STAB entries. The real parsing is
/// done in handleStabSymbolTableEntry. /// done in handleStabSymbolTableEntry.
ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() { ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
auto MainBinOrError = MainBinaryHolder.GetFileAs<MachOObjectFile>(BinaryPath); auto MainBinOrError =
MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
if (auto Error = MainBinOrError.getError()) if (auto Error = MainBinOrError.getError())
return Error; return Error;
const MachOObjectFile &MainBinary = *MainBinOrError; if (MainBinOrError->size() != 1)
loadMainBinarySymbols(); return make_error_code(object::object_error::invalid_file_type);
const MachOObjectFile &MainBinary = *MainBinOrError->front();
loadMainBinarySymbols(MainBinary);
Result = make_unique<DebugMap>(BinaryHolder::getTriple(MainBinary)); Result = make_unique<DebugMap>(BinaryHolder::getTriple(MainBinary));
MainBinaryStrings = MainBinary.getStringTableData(); MainBinaryStrings = MainBinary.getStringTableData();
for (const SymbolRef &Symbol : MainBinary.symbols()) { for (const SymbolRef &Symbol : MainBinary.symbols()) {
@@ -189,10 +200,11 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
} }
/// Load the current object file symbols into CurrentObjectAddresses. /// Load the current object file symbols into CurrentObjectAddresses.
void MachODebugMapParser::loadCurrentObjectFileSymbols() { void MachODebugMapParser::loadCurrentObjectFileSymbols(
const object::MachOObjectFile &Obj) {
CurrentObjectAddresses.clear(); CurrentObjectAddresses.clear();
for (auto Sym : CurrentObjectHolder.Get().symbols()) { for (auto Sym : Obj.symbols()) {
uint64_t Addr = Sym.getValue(); uint64_t Addr = Sym.getValue();
ErrorOr<StringRef> Name = Sym.getName(); ErrorOr<StringRef> Name = Sym.getName();
if (!Name) if (!Name)
@@ -213,9 +225,10 @@ uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
/// Load the interesting main binary symbols' addresses into /// Load the interesting main binary symbols' addresses into
/// MainBinarySymbolAddresses. /// MainBinarySymbolAddresses.
void MachODebugMapParser::loadMainBinarySymbols() { void MachODebugMapParser::loadMainBinarySymbols(
const MachOObjectFile &MainBinary = MainBinaryHolder.GetAs<MachOObjectFile>(); const MachOObjectFile &MainBinary) {
section_iterator Section = MainBinary.section_end(); section_iterator Section = MainBinary.section_end();
MainBinarySymbolAddresses.clear();
for (const auto &Sym : MainBinary.symbols()) { for (const auto &Sym : MainBinary.symbols()) {
SymbolRef::Type Type = Sym.getType(); SymbolRef::Type Type = Sym.getType();
// Skip undefined and STAB entries. // Skip undefined and STAB entries.