blob: cab9374a7d97477a3543422bcc93fd81bb7efb3e [file] [log] [blame]
Jonas Devlieghere20767d12019-01-07 23:27:25 +00001//===- 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
23namespace llvm {
24namespace dsymutil {
25
26StringRef 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
63SymbolMapTranslator 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