forked from llvm-mirror/llvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[dsymutil] Implement the BinaryHolder object and gain archive support.
This object is meant to own the ObjectFiles and their underlying MemoryBuffer. It is basically the equivalent of an OwningBinary except that it efficiently handles Archives. It is optimized for efficiently providing mappings of members of the same archive when they are opened successively (which is standard in Darwin debug maps, objects from the same archive will be contiguous). Of course, the BinaryHolder will also be used by the DWARF linker once it is commited, but for now only the debug map parser uses it. With this change, you can run llvm-dsymutil on your Darwin debug build of clang and get a complete debug map for it. Differential Revision: http://reviews.llvm.org/D6690 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225207 91177308-0d34-0410-b5e6-96231b3b80d8
- Loading branch information
Showing
8 changed files
with
265 additions
and
34 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
//===-- BinaryHolder.cpp --------------------------------------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This program is a utility that aims to be a dropin replacement for | ||
// Darwin's dsymutil. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "BinaryHolder.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
namespace llvm { | ||
namespace dsymutil { | ||
|
||
ErrorOr<MemoryBufferRef> | ||
BinaryHolder::GetMemoryBufferForFile(StringRef Filename) { | ||
if (Verbose) | ||
outs() << "trying to open '" << Filename << "'\n"; | ||
|
||
// Try that first as it doesn't involve any filesystem access. | ||
if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename)) | ||
return *ErrOrArchiveMember; | ||
|
||
// If the name ends with a closing paren, there is a huge chance | ||
// it is an archive member specification. | ||
if (Filename.endswith(")")) | ||
if (auto ErrOrArchiveMember = MapArchiveAndGetMemberBuffer(Filename)) | ||
return *ErrOrArchiveMember; | ||
|
||
// Otherwise, just try opening a standard file. If this is an | ||
// archive member specifiaction and any of the above didn't handle it | ||
// (either because the archive is not there anymore, or because the | ||
// archive doesn't contain the requested member), this will still | ||
// provide a sensible error message. | ||
auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename); | ||
if (auto Err = ErrOrFile.getError()) | ||
return Err; | ||
|
||
if (Verbose) | ||
outs() << "\tloaded file.\n"; | ||
CurrentArchive.reset(); | ||
CurrentMemoryBuffer = std::move(ErrOrFile.get()); | ||
return CurrentMemoryBuffer->getMemBufferRef(); | ||
} | ||
|
||
ErrorOr<MemoryBufferRef> | ||
BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { | ||
if (!CurrentArchive) | ||
return make_error_code(errc::no_such_file_or_directory); | ||
|
||
StringRef CurArchiveName = CurrentArchive->getFileName(); | ||
if (!Filename.startswith(Twine(CurArchiveName, "(").str())) | ||
return make_error_code(errc::no_such_file_or_directory); | ||
|
||
// Remove the archive name and the parens around the archive member name. | ||
Filename = Filename.substr(CurArchiveName.size() + 1).drop_back(); | ||
|
||
for (const auto &Child : CurrentArchive->children()) { | ||
if (auto NameOrErr = Child.getName()) | ||
if (*NameOrErr == Filename) { | ||
if (Verbose) | ||
outs() << "\tfound member in current archive.\n"; | ||
return Child.getMemoryBufferRef(); | ||
} | ||
} | ||
|
||
return make_error_code(errc::no_such_file_or_directory); | ||
} | ||
|
||
ErrorOr<MemoryBufferRef> | ||
BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) { | ||
StringRef ArchiveFilename = Filename.substr(0, Filename.find('(')); | ||
|
||
auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename); | ||
if (auto Err = ErrOrBuff.getError()) | ||
return Err; | ||
|
||
if (Verbose) | ||
outs() << "\topened new archive '" << ArchiveFilename << "'\n"; | ||
auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef()); | ||
if (auto Err = ErrOrArchive.getError()) | ||
return Err; | ||
|
||
CurrentArchive = std::move(*ErrOrArchive); | ||
CurrentMemoryBuffer = std::move(*ErrOrBuff); | ||
|
||
return GetArchiveMemberBuffer(Filename); | ||
} | ||
|
||
ErrorOr<const object::ObjectFile &> | ||
BinaryHolder::GetObjectFile(StringRef Filename) { | ||
auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename); | ||
if (auto Err = ErrOrMemBufferRef.getError()) | ||
return Err; | ||
|
||
auto ErrOrObjectFile = | ||
object::ObjectFile::createObjectFile(*ErrOrMemBufferRef); | ||
if (auto Err = ErrOrObjectFile.getError()) | ||
return Err; | ||
|
||
CurrentObjectFile = std::move(*ErrOrObjectFile); | ||
return *CurrentObjectFile; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
//===-- BinaryHolder.h - Utility class for accessing binaries -------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This program is a utility that aims to be a dropin replacement for | ||
// Darwin's dsymutil. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H | ||
#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H | ||
|
||
#include "llvm/Object/Archive.h" | ||
#include "llvm/Object/Error.h" | ||
#include "llvm/Object/ObjectFile.h" | ||
#include "llvm/Support/Errc.h" | ||
#include "llvm/Support/ErrorOr.h" | ||
|
||
namespace llvm { | ||
namespace dsymutil { | ||
|
||
/// \brief The BinaryHolder class is responsible for creating and | ||
/// owning ObjectFile objects and their underlying MemoryBuffer. This | ||
/// is different from a simple OwningBinary in that it handles | ||
/// accessing to archive members. | ||
/// | ||
/// As an optimization, this class will reuse an already mapped and | ||
/// parsed Archive object if 2 successive requests target the same | ||
/// archive file (Which is always the case in debug maps). | ||
/// Currently it only owns one memory buffer at any given time, | ||
/// meaning that a mapping request will invalidate the previous memory | ||
/// mapping. | ||
class BinaryHolder { | ||
std::unique_ptr<object::Archive> CurrentArchive; | ||
std::unique_ptr<MemoryBuffer> CurrentMemoryBuffer; | ||
std::unique_ptr<object::ObjectFile> CurrentObjectFile; | ||
bool Verbose; | ||
|
||
/// \brief Get the MemoryBufferRef for the file specification in \p | ||
/// Filename from the current archive. | ||
/// | ||
/// This function performs no system calls, it just looks up a | ||
/// potential match for the given \p Filename in the currently | ||
/// mapped archive if there is one. | ||
ErrorOr<MemoryBufferRef> GetArchiveMemberBuffer(StringRef Filename); | ||
|
||
/// \brief Interpret Filename as an archive member specification, | ||
/// map the corresponding archive to memory and return the | ||
/// MemoryBufferRef corresponding to the described member. | ||
ErrorOr<MemoryBufferRef> MapArchiveAndGetMemberBuffer(StringRef Filename); | ||
|
||
/// \brief Return the MemoryBufferRef that holds the memory | ||
/// mapping for the given \p Filename. This function will try to | ||
/// parse archive member specifications of the form | ||
/// /path/to/archive.a(member.o). | ||
/// | ||
/// The returned MemoryBufferRef points to a buffer owned by this | ||
/// object. The buffer is valid until the next call to | ||
/// GetMemoryBufferForFile() on this object. | ||
ErrorOr<MemoryBufferRef> GetMemoryBufferForFile(StringRef Filename); | ||
|
||
public: | ||
BinaryHolder(bool Verbose) : Verbose(Verbose) {} | ||
|
||
/// \brief Get the ObjectFile designated by the \p Filename. This | ||
/// might be an archive member specification of the form | ||
/// /path/to/archive.a(member.o). | ||
/// | ||
/// Calling this function invalidates the previous mapping owned by | ||
/// the BinaryHolder. | ||
ErrorOr<const object::ObjectFile &> GetObjectFile(StringRef Filename); | ||
|
||
/// \brief Wraps GetObjectFile() to return a derived ObjectFile type. | ||
template <typename ObjectFileType> | ||
ErrorOr<const ObjectFileType &> GetFileAs(StringRef Filename) { | ||
auto ErrOrObjFile = GetObjectFile(Filename); | ||
if (auto Err = ErrOrObjFile.getError()) | ||
return Err; | ||
if (const auto *Derived = dyn_cast<ObjectFileType>(CurrentObjectFile.get())) | ||
return *Derived; | ||
return make_error_code(object::object_error::invalid_file_type); | ||
} | ||
|
||
/// \brief Access the currently owned ObjectFile. As successfull | ||
/// call to GetObjectFile() or GetFileAs() must have been performed | ||
/// before calling this. | ||
const object::ObjectFile &Get() { | ||
assert(CurrentObjectFile); | ||
return *CurrentObjectFile; | ||
} | ||
|
||
/// \brief Access to a derived version of the currently owned | ||
/// ObjectFile. The conversion must be known to be valid. | ||
template <typename ObjectFileType> const ObjectFileType &GetAs() { | ||
return cast<ObjectFileType>(*CurrentObjectFile); | ||
} | ||
}; | ||
} | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.