llvm-project/llvm/tools/dsymutil/SymbolMap.cpp
John McCall 984744a131 Fix a variety of minor issues with ObjC method mangling:
- Fix a memory leak accidentally introduced yesterday by using CodeGen's
  existing mangling context instead of creating a new context afresh.

- Move GNU-runtime ObjC method mangling into the AST mangler; this will
  eventually be necessary to support direct methods there, but is also
  just the right architecture.

- Make the Apple-runtime method mangling work properly when given an
  interface declaration, fixing a bug (which had solidified into a test)
  where mangling a category method from the interface could cause it to
  be mangled as if the category name was a class name.  (Category names
  are namespaced within their class and have no global meaning.)

- Fix a code cross-reference in dsymutil.

Based on a patch by Ellis Hoag.
2020-09-29 19:51:53 -04:00

162 lines
5.6 KiB
C++

//===- tools/dsymutil/SymbolMap.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
//
//===----------------------------------------------------------------------===//
#include "SymbolMap.h"
#include "DebugMap.h"
#include "MachOUtils.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/WithColor.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <uuid/uuid.h>
#endif
namespace llvm {
namespace dsymutil {
StringRef SymbolMapTranslator::operator()(StringRef Input) {
if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#"))
return Input;
bool MightNeedUnderscore = false;
StringRef Line = Input.drop_front(sizeof("__hidden#") - 1);
if (Line[0] == '#') {
Line = Line.drop_front();
MightNeedUnderscore = true;
}
std::size_t LineNumber = std::numeric_limits<std::size_t>::max();
Line.split('_').first.getAsInteger(10, LineNumber);
if (LineNumber >= UnobfuscatedStrings.size()) {
WithColor::warning() << "reference to a unexisting unobfuscated string "
<< Input << ": symbol map mismatch?\n"
<< Line << '\n';
return Input;
}
const std::string &Translation = UnobfuscatedStrings[LineNumber];
if (!MightNeedUnderscore || !MangleNames)
return Translation;
// Objective-C symbols for the MachO symbol table start with a \1. Please see
// `MangleContext::mangleObjCMethodName` in clang.
if (Translation[0] == 1)
return StringRef(Translation).drop_front();
// We need permanent storage for the string we are about to create. Just
// append it to the vector containing translations. This should only happen
// during MachO symbol table translation, thus there should be no risk on
// exponential growth.
UnobfuscatedStrings.emplace_back("_" + Translation);
return UnobfuscatedStrings.back();
}
SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile,
const DebugMap &Map) const {
if (SymbolMap.empty())
return {};
std::string SymbolMapPath = SymbolMap;
#if __APPLE__
// Look through the UUID Map.
if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) {
uuid_string_t UUIDString;
uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString);
SmallString<256> PlistPath(
sys::path::parent_path(sys::path::parent_path(InputFile)));
sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist");
CFStringRef plistFile = CFStringCreateWithCString(
kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8);
CFURLRef fileURL = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false);
CFReadStreamRef resourceData =
CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
if (resourceData) {
CFReadStreamOpen(resourceData);
CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream(
kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable,
nullptr, nullptr);
if (plist) {
if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) {
CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue(
plist, CFSTR("DBGOriginalUUID"));
StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8));
SmallString<256> BCSymbolMapPath(SymbolMapPath);
sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap");
SymbolMapPath = std::string(BCSymbolMapPath);
}
CFRelease(plist);
}
CFReadStreamClose(resourceData);
CFRelease(resourceData);
}
CFRelease(fileURL);
CFRelease(plistFile);
}
#endif
if (sys::fs::is_directory(SymbolMapPath)) {
SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" +
MachOUtils::getArchName(Map.getTriple().getArchName()) +
".bcsymbolmap")
.str();
}
auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath);
if (auto EC = ErrOrMemBuffer.getError()) {
WithColor::warning() << SymbolMapPath << ": " << EC.message()
<< ": not unobfuscating.\n";
return {};
}
std::vector<std::string> UnobfuscatedStrings;
auto &MemBuf = **ErrOrMemBuffer;
StringRef Data(MemBuf.getBufferStart(),
MemBuf.getBufferEnd() - MemBuf.getBufferStart());
StringRef LHS;
std::tie(LHS, Data) = Data.split('\n');
bool MangleNames = false;
// Check version string first.
if (!LHS.startswith("BCSymbolMap Version:")) {
// Version string not present, warns but try to parse it.
WithColor::warning() << SymbolMapPath
<< " is missing version string: assuming 1.0.\n";
UnobfuscatedStrings.emplace_back(LHS);
} else if (LHS.equals("BCSymbolMap Version: 1.0")) {
MangleNames = true;
} else if (LHS.equals("BCSymbolMap Version: 2.0")) {
MangleNames = false;
} else {
StringRef VersionNum;
std::tie(LHS, VersionNum) = LHS.split(':');
WithColor::warning() << SymbolMapPath
<< " has unsupported symbol map version" << VersionNum
<< ": not unobfuscating.\n";
return {};
}
while (!Data.empty()) {
std::tie(LHS, Data) = Data.split('\n');
UnobfuscatedStrings.emplace_back(LHS);
}
return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames);
}
} // namespace dsymutil
} // namespace llvm