| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 
 | //===- 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
  // `CGObjCCommonMac::GetNameForMethod` 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
 |