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 163