Jonas Devlieghere | 20767d1 | 2019-01-07 23:27:25 +0000 | [diff] [blame] | 1 | //===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "SymbolMap.h" |
| 11 | #include "DebugMap.h" |
| 12 | #include "MachOUtils.h" |
| 13 | |
| 14 | #include "llvm/Support/FileSystem.h" |
| 15 | #include "llvm/Support/Path.h" |
| 16 | #include "llvm/Support/WithColor.h" |
| 17 | |
| 18 | #ifdef __APPLE__ |
| 19 | #include <CoreFoundation/CoreFoundation.h> |
| 20 | #include <uuid/uuid.h> |
| 21 | #endif |
| 22 | |
| 23 | namespace llvm { |
| 24 | namespace dsymutil { |
| 25 | |
| 26 | StringRef SymbolMapTranslator::operator()(StringRef Input) { |
| 27 | if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#")) |
| 28 | return Input; |
| 29 | |
| 30 | bool MightNeedUnderscore = false; |
| 31 | StringRef Line = Input.drop_front(sizeof("__hidden#") - 1); |
| 32 | if (Line[0] == '#') { |
| 33 | Line = Line.drop_front(); |
| 34 | MightNeedUnderscore = true; |
| 35 | } |
| 36 | |
| 37 | std::size_t LineNumber = std::numeric_limits<std::size_t>::max(); |
| 38 | Line.split('_').first.getAsInteger(10, LineNumber); |
| 39 | if (LineNumber >= UnobfuscatedStrings.size()) { |
| 40 | WithColor::warning() << "reference to a unexisting unobfuscated string " |
| 41 | << Input << ": symbol map mismatch?\n" |
| 42 | << Line << '\n'; |
| 43 | return Input; |
| 44 | } |
| 45 | |
| 46 | const std::string &Translation = UnobfuscatedStrings[LineNumber]; |
| 47 | if (!MightNeedUnderscore || !MangleNames) |
| 48 | return Translation; |
| 49 | |
| 50 | // Objective-C symbols for the MachO symbol table start with a \1. Please see |
| 51 | // `CGObjCCommonMac::GetNameForMethod` in clang. |
| 52 | if (Translation[0] == 1) |
| 53 | return StringRef(Translation).drop_front(); |
| 54 | |
| 55 | // We need permanent storage for the string we are about to create. Just |
| 56 | // append it to the vector containing translations. This should only happen |
| 57 | // during MachO symbol table translation, thus there should be no risk on |
| 58 | // exponential growth. |
| 59 | UnobfuscatedStrings.emplace_back("_" + Translation); |
| 60 | return UnobfuscatedStrings.back(); |
| 61 | } |
| 62 | |
| 63 | SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile, |
| 64 | const DebugMap &Map) const { |
| 65 | if (SymbolMap.empty()) |
| 66 | return {}; |
| 67 | |
| 68 | std::string SymbolMapPath = SymbolMap; |
| 69 | |
| 70 | #if __APPLE__ |
| 71 | // Look through the UUID Map. |
| 72 | if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) { |
| 73 | uuid_string_t UUIDString; |
| 74 | uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString); |
| 75 | |
| 76 | SmallString<256> PlistPath( |
| 77 | sys::path::parent_path(sys::path::parent_path(InputFile))); |
| 78 | sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist"); |
| 79 | |
| 80 | CFStringRef plistFile = CFStringCreateWithCString( |
| 81 | kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8); |
| 82 | CFURLRef fileURL = CFURLCreateWithFileSystemPath( |
| 83 | kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false); |
| 84 | CFReadStreamRef resourceData = |
| 85 | CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); |
| 86 | if (resourceData) { |
| 87 | CFReadStreamOpen(resourceData); |
| 88 | CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream( |
| 89 | kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable, |
| 90 | nullptr, nullptr); |
| 91 | |
| 92 | if (plist) { |
| 93 | if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) { |
| 94 | CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue( |
| 95 | plist, CFSTR("DBGOriginalUUID")); |
| 96 | |
| 97 | StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8)); |
| 98 | SmallString<256> BCSymbolMapPath(SymbolMapPath); |
| 99 | sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap"); |
| 100 | SymbolMapPath = BCSymbolMapPath.str(); |
| 101 | } |
| 102 | CFRelease(plist); |
| 103 | } |
| 104 | CFReadStreamClose(resourceData); |
| 105 | CFRelease(resourceData); |
| 106 | } |
| 107 | CFRelease(fileURL); |
| 108 | CFRelease(plistFile); |
| 109 | } |
| 110 | #endif |
| 111 | |
| 112 | if (sys::fs::is_directory(SymbolMapPath)) { |
| 113 | SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" + |
| 114 | MachOUtils::getArchName(Map.getTriple().getArchName()) + |
| 115 | ".bcsymbolmap") |
| 116 | .str(); |
| 117 | } |
| 118 | |
| 119 | auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath); |
| 120 | if (auto EC = ErrOrMemBuffer.getError()) { |
| 121 | WithColor::warning() << SymbolMapPath << ": " << EC.message() |
| 122 | << ": not unobfuscating.\n"; |
| 123 | return {}; |
| 124 | } |
| 125 | |
| 126 | std::vector<std::string> UnobfuscatedStrings; |
| 127 | auto &MemBuf = **ErrOrMemBuffer; |
| 128 | StringRef Data(MemBuf.getBufferStart(), |
| 129 | MemBuf.getBufferEnd() - MemBuf.getBufferStart()); |
| 130 | StringRef LHS; |
| 131 | std::tie(LHS, Data) = Data.split('\n'); |
| 132 | bool MangleNames = false; |
| 133 | |
| 134 | // Check version string first. |
| 135 | if (!LHS.startswith("BCSymbolMap Version:")) { |
| 136 | // Version string not present, warns but try to parse it. |
| 137 | WithColor::warning() << SymbolMapPath |
| 138 | << " is missing version string: assuming 1.0.\n"; |
| 139 | UnobfuscatedStrings.emplace_back(LHS); |
| 140 | } else if (LHS.equals("BCSymbolMap Version: 1.0")) { |
| 141 | MangleNames = true; |
| 142 | } else if (LHS.equals("BCSymbolMap Version: 2.0")) { |
| 143 | MangleNames = false; |
| 144 | } else { |
| 145 | StringRef VersionNum; |
| 146 | std::tie(LHS, VersionNum) = LHS.split(':'); |
| 147 | WithColor::warning() << SymbolMapPath |
| 148 | << " has unsupported symbol map version" << VersionNum |
| 149 | << ": not unobfuscating.\n"; |
| 150 | return {}; |
| 151 | } |
| 152 | |
| 153 | while (!Data.empty()) { |
| 154 | std::tie(LHS, Data) = Data.split('\n'); |
| 155 | UnobfuscatedStrings.emplace_back(LHS); |
| 156 | } |
| 157 | |
| 158 | return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames); |
| 159 | } |
| 160 | |
| 161 | } // namespace dsymutil |
| 162 | } // namespace llvm |