[Symbolize] Improve the ownership of parsed objects.

This code changes the way Symbolize handles parsed binaries: now
parsed OwningBinary<Binary> is not broken into (binary, memory buffer)
pair, and is just stored as-is in a cache. ObjectFile components
of Mach-O universal binaries are also stored explicitly in a
separate cache.

Additionally, this change:
* simplifies the code that parses/caches binaries: it's now done
  in a single place, not three different functions.
* makes flush() method behave as expected, and actually clear
  the cached parsed binaries and objects.
* fixes a dangling pointer issue described in
  http://reviews.llvm.org/D15638

llvm-svn: 256041
This commit is contained in:
Alexey Samsonov 2015-12-18 22:02:14 +00:00
parent 718a9b2844
commit 1eaae4c3b1
2 changed files with 67 additions and 71 deletions

View File

@ -13,13 +13,9 @@
#ifndef LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
#define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include <map>
#include <memory>
#include <string>
@ -63,6 +59,8 @@ public:
const SymbolizableModule *ModInfo);
private:
// Bundles together object file with code/data and object file with
// corresponding debug info. These objects can be the same.
typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair;
ErrorOr<SymbolizableModule *>
@ -75,30 +73,29 @@ private:
const std::string &ArchName);
/// \brief Returns pair of pointers to object and debug object.
ErrorOr<ObjectPair> getOrCreateObjects(const std::string &Path,
const std::string &ArchName);
/// \brief Returns a parsed object file for a given architecture in a
/// universal binary (or the binary itself if it is an object file).
ErrorOr<ObjectFile *> getObjectFileFromBinary(Binary *Bin,
const std::string &ArchName);
ErrorOr<ObjectPair> getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName);
// Owns all the parsed binaries and object files.
SmallVector<std::unique_ptr<Binary>, 4> ParsedBinariesAndObjects;
SmallVector<std::unique_ptr<MemoryBuffer>, 4> MemoryBuffers;
void addOwningBinary(OwningBinary<Binary> OwningBin) {
std::unique_ptr<Binary> Bin;
std::unique_ptr<MemoryBuffer> MemBuf;
std::tie(Bin, MemBuf) = OwningBin.takeBinary();
ParsedBinariesAndObjects.push_back(std::move(Bin));
MemoryBuffers.push_back(std::move(MemBuf));
}
/// \brief Return a pointer to object file at specified path, for a specified
/// architecture (e.g. if path refers to a Mach-O universal binary, only one
/// object file from it will be returned).
ErrorOr<ObjectFile *> getOrCreateObject(const std::string &Path,
const std::string &ArchName);
std::map<std::string, ErrorOr<std::unique_ptr<SymbolizableModule>>> Modules;
std::map<std::pair<MachOUniversalBinary *, std::string>,
ErrorOr<ObjectFile *>> ObjectFileForArch;
/// \brief Contains cached results of getOrCreateObjectPair().
std::map<std::pair<std::string, std::string>, ErrorOr<ObjectPair>>
ObjectPairForPathArch;
/// \brief Contains parsed binary for each path, or parsing error.
std::map<std::string, ErrorOr<OwningBinary<Binary>>> BinaryForPath;
/// \brief Parsed object file for path/architecture pair, where "path" refers
/// to Mach-O universal binary.
std::map<std::pair<std::string, std::string>, ErrorOr<std::unique_ptr<ObjectFile>>>
ObjectForUBPathAndArch;
Options Opts;
};

View File

@ -22,6 +22,7 @@
#include "llvm/DebugInfo/PDB/PDBContext.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compression.h"
@ -109,9 +110,10 @@ ErrorOr<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
}
void LLVMSymbolizer::flush() {
Modules.clear();
ObjectForUBPathAndArch.clear();
BinaryForPath.clear();
ObjectPairForPathArch.clear();
ObjectFileForArch.clear();
Modules.clear();
}
// For Path="/path/to/foo" and Basename="foo" assume that debug info is in
@ -223,23 +225,16 @@ ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
for (const auto &Path : Opts.DsymHints) {
DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
}
for (const auto &path : DsymPaths) {
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path);
if (!BinaryOrErr)
continue;
OwningBinary<Binary> &B = BinaryOrErr.get();
auto DbgObjOrErr = getObjectFileFromBinary(B.getBinary(), ArchName);
for (const auto &Path : DsymPaths) {
auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
if (!DbgObjOrErr)
continue;
ObjectFile *DbgObj = DbgObjOrErr.get();
const MachOObjectFile *MachDbgObj =
dyn_cast<const MachOObjectFile>(DbgObj);
const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
if (!MachDbgObj)
continue;
if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) {
addOwningBinary(std::move(B));
if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
return DbgObj;
}
}
return nullptr;
}
@ -254,40 +249,25 @@ ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
return nullptr;
if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
return nullptr;
ErrorOr<OwningBinary<Binary>> DebugBinaryOrErr =
createBinary(DebugBinaryPath);
if (!DebugBinaryOrErr)
return nullptr;
OwningBinary<Binary> &DB = DebugBinaryOrErr.get();
auto DbgObjOrErr = getObjectFileFromBinary(DB.getBinary(), ArchName);
auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
if (!DbgObjOrErr)
return nullptr;
addOwningBinary(std::move(DB));
return DbgObjOrErr.get();
}
ErrorOr<LLVMSymbolizer::ObjectPair>
LLVMSymbolizer::getOrCreateObjects(const std::string &Path,
const std::string &ArchName) {
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName) {
const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
if (I != ObjectPairForPathArch.end())
return I->second;
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path);
if (auto EC = BinaryOrErr.getError()) {
ObjectPairForPathArch.insert(
std::make_pair(std::make_pair(Path, ArchName), EC));
return EC;
}
OwningBinary<Binary> &B = BinaryOrErr.get();
auto ObjOrErr = getObjectFileFromBinary(B.getBinary(), ArchName);
auto ObjOrErr = getOrCreateObject(Path, ArchName);
if (auto EC = ObjOrErr.getError()) {
ObjectPairForPathArch.insert(
std::make_pair(std::make_pair(Path, ArchName), EC));
return EC;
}
addOwningBinary(std::move(B));
ObjectFile *Obj = ObjOrErr.get();
assert(Obj != nullptr);
@ -306,24 +286,43 @@ LLVMSymbolizer::getOrCreateObjects(const std::string &Path,
}
ErrorOr<ObjectFile *>
LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin,
const std::string &ArchName) {
assert(Bin != nullptr);
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
const auto &I = ObjectFileForArch.find(
std::make_pair(UB, ArchName));
if (I != ObjectFileForArch.end())
return I->second;
ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj =
UB->getObjectForArch(ArchName);
if (auto EC = ParsedObj.getError()) {
ObjectFileForArch.insert(
std::make_pair(std::make_pair(UB, ArchName), EC));
LLVMSymbolizer::getOrCreateObject(const std::string &Path,
const std::string &ArchName) {
const auto &I = BinaryForPath.find(Path);
Binary *Bin = nullptr;
if (I == BinaryForPath.end()) {
ErrorOr<OwningBinary<Binary>> BinOrErr = createBinary(Path);
if (auto EC = BinOrErr.getError()) {
BinaryForPath.insert(std::make_pair(Path, EC));
return EC;
}
ObjectFile *Res = ParsedObj.get().get();
ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get()));
ObjectFileForArch.insert(std::make_pair(std::make_pair(UB, ArchName), Res));
Bin = BinOrErr->getBinary();
BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
} else if (auto EC = I->second.getError()) {
return EC;
} else {
Bin = I->second->getBinary();
}
assert(Bin != nullptr);
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
if (I != ObjectForUBPathAndArch.end()) {
if (auto EC = I->second.getError())
return EC;
return I->second->get();
}
ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
UB->getObjectForArch(ArchName);
if (auto EC = ObjOrErr.getError()) {
ObjectForUBPathAndArch.insert(
std::make_pair(std::make_pair(Path, ArchName), EC));
return EC;
}
ObjectFile *Res = ObjOrErr->get();
ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
std::move(ObjOrErr.get())));
return Res;
}
if (Bin->isObject()) {
@ -352,7 +351,7 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
ArchName = ArchStr;
}
}
auto ObjectsOrErr = getOrCreateObjects(BinaryName, ArchName);
auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
if (auto EC = ObjectsOrErr.getError()) {
// Failed to find valid object file.
Modules.insert(std::make_pair(ModuleName, EC));