1 //===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "MachOUtils.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Path.h"
15 #include "llvm/Support/WithColor.h"
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <uuid/uuid.h>
25 StringRef
SymbolMapTranslator::operator()(StringRef Input
) {
26 if (!Input
.startswith("__hidden#") && !Input
.startswith("___hidden#"))
29 bool MightNeedUnderscore
= false;
30 StringRef Line
= Input
.drop_front(sizeof("__hidden#") - 1);
32 Line
= Line
.drop_front();
33 MightNeedUnderscore
= true;
36 std::size_t LineNumber
= std::numeric_limits
<std::size_t>::max();
37 Line
.split('_').first
.getAsInteger(10, LineNumber
);
38 if (LineNumber
>= UnobfuscatedStrings
.size()) {
39 WithColor::warning() << "reference to a unexisting unobfuscated string "
40 << Input
<< ": symbol map mismatch?\n"
45 const std::string
&Translation
= UnobfuscatedStrings
[LineNumber
];
46 if (!MightNeedUnderscore
|| !MangleNames
)
49 // Objective-C symbols for the MachO symbol table start with a \1. Please see
50 // `CGObjCCommonMac::GetNameForMethod` in clang.
51 if (Translation
[0] == 1)
52 return StringRef(Translation
).drop_front();
54 // We need permanent storage for the string we are about to create. Just
55 // append it to the vector containing translations. This should only happen
56 // during MachO symbol table translation, thus there should be no risk on
57 // exponential growth.
58 UnobfuscatedStrings
.emplace_back("_" + Translation
);
59 return UnobfuscatedStrings
.back();
62 SymbolMapTranslator
SymbolMapLoader::Load(StringRef InputFile
,
63 const DebugMap
&Map
) const {
64 if (SymbolMap
.empty())
67 std::string SymbolMapPath
= SymbolMap
;
70 // Look through the UUID Map.
71 if (sys::fs::is_directory(SymbolMapPath
) && !Map
.getUUID().empty()) {
72 uuid_string_t UUIDString
;
73 uuid_unparse_upper((const uint8_t *)Map
.getUUID().data(), UUIDString
);
75 SmallString
<256> PlistPath(
76 sys::path::parent_path(sys::path::parent_path(InputFile
)));
77 sys::path::append(PlistPath
, StringRef(UUIDString
).str() + ".plist");
79 CFStringRef plistFile
= CFStringCreateWithCString(
80 kCFAllocatorDefault
, PlistPath
.c_str(), kCFStringEncodingUTF8
);
81 CFURLRef fileURL
= CFURLCreateWithFileSystemPath(
82 kCFAllocatorDefault
, plistFile
, kCFURLPOSIXPathStyle
, false);
83 CFReadStreamRef resourceData
=
84 CFReadStreamCreateWithFile(kCFAllocatorDefault
, fileURL
);
86 CFReadStreamOpen(resourceData
);
87 CFDictionaryRef plist
= (CFDictionaryRef
)CFPropertyListCreateWithStream(
88 kCFAllocatorDefault
, resourceData
, 0, kCFPropertyListImmutable
,
92 if (CFDictionaryContainsKey(plist
, CFSTR("DBGOriginalUUID"))) {
93 CFStringRef OldUUID
= (CFStringRef
)CFDictionaryGetValue(
94 plist
, CFSTR("DBGOriginalUUID"));
96 StringRef
UUID(CFStringGetCStringPtr(OldUUID
, kCFStringEncodingUTF8
));
97 SmallString
<256> BCSymbolMapPath(SymbolMapPath
);
98 sys::path::append(BCSymbolMapPath
, UUID
.str() + ".bcsymbolmap");
99 SymbolMapPath
= BCSymbolMapPath
.str();
103 CFReadStreamClose(resourceData
);
104 CFRelease(resourceData
);
107 CFRelease(plistFile
);
111 if (sys::fs::is_directory(SymbolMapPath
)) {
112 SymbolMapPath
+= (Twine("/") + sys::path::filename(InputFile
) + "-" +
113 MachOUtils::getArchName(Map
.getTriple().getArchName()) +
118 auto ErrOrMemBuffer
= MemoryBuffer::getFile(SymbolMapPath
);
119 if (auto EC
= ErrOrMemBuffer
.getError()) {
120 WithColor::warning() << SymbolMapPath
<< ": " << EC
.message()
121 << ": not unobfuscating.\n";
125 std::vector
<std::string
> UnobfuscatedStrings
;
126 auto &MemBuf
= **ErrOrMemBuffer
;
127 StringRef
Data(MemBuf
.getBufferStart(),
128 MemBuf
.getBufferEnd() - MemBuf
.getBufferStart());
130 std::tie(LHS
, Data
) = Data
.split('\n');
131 bool MangleNames
= false;
133 // Check version string first.
134 if (!LHS
.startswith("BCSymbolMap Version:")) {
135 // Version string not present, warns but try to parse it.
136 WithColor::warning() << SymbolMapPath
137 << " is missing version string: assuming 1.0.\n";
138 UnobfuscatedStrings
.emplace_back(LHS
);
139 } else if (LHS
.equals("BCSymbolMap Version: 1.0")) {
141 } else if (LHS
.equals("BCSymbolMap Version: 2.0")) {
144 StringRef VersionNum
;
145 std::tie(LHS
, VersionNum
) = LHS
.split(':');
146 WithColor::warning() << SymbolMapPath
147 << " has unsupported symbol map version" << VersionNum
148 << ": not unobfuscating.\n";
152 while (!Data
.empty()) {
153 std::tie(LHS
, Data
) = Data
.split('\n');
154 UnobfuscatedStrings
.emplace_back(LHS
);
157 return SymbolMapTranslator(std::move(UnobfuscatedStrings
), MangleNames
);
160 } // namespace dsymutil