1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00

[dsymutil] Upstream unobfuscation logic.

The unobufscation support for BCSymbolMaps was the last piece of code
that hasn't been upstreamed yet. This patch contains a reworked version
of the existing code and relevant tests.

Differential revision: https://reviews.llvm.org/D56346

llvm-svn: 350580
This commit is contained in:
Jonas Devlieghere 2019-01-07 23:27:25 +00:00
parent 3c60a06881
commit acf6a4feab
21 changed files with 601 additions and 28 deletions

View File

@ -0,0 +1,166 @@
REQUIRES: system-darwin
RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
RUN: | llvm-dwarfdump -v - \
RUN: | FileCheck %s
RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.map %p/../Inputs/obfuscated.arm64 -f -o - \
RUN: | llvm-dwarfdump -v - \
RUN: | FileCheck --check-prefix=NOHIDDEN %s
RUN: dsymutil --symbol-map %p/../Inputs/obfuscated.2.map %p/../Inputs/obfuscated.2.arm64 -f -o - \
RUN: | llvm-dwarfdump -v - \
RUN: | FileCheck --check-prefix=NOHIDDEN %s
// Run with plist and make sure dsymutil finds it.
RUN: mkdir -p %t.dSYM/Contents/Resources/DWARF/
RUN: mkdir -p %t.mapdir
RUN: cp %p/../Inputs/obfuscated.arm64 %t.dSYM/Contents/Resources/DWARF/
RUN: cp %p/../Inputs/E828A486-8433-3A5E-B6DB-A6294D28133D.plist %t.dSYM/Contents/Resources/
RUN: cp %p/../Inputs/obfuscated.map %t.mapdir/506AA50A-6B26-3B37-86D2-DC6EBD57B720.bcsymbolmap
RUN: dsymutil --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=OBFUSCATING %s
// Run without plist and make sure dsymutil doesn't crash.
RUN: rm %t.dSYM/Contents/Resources/E828A486-8433-3A5E-B6DB-A6294D28133D.plist
RUN: dsymutil --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=NOTOBFUSCATING %s
OBFUSCATING-NOT: not unobfuscating
NOTOBFUSCATING: not unobfuscating
NOHIDDEN-NOT: __hidden#
CHECK: .debug_info contents:
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "main.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "main")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "one.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "one")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "two.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "two")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "three.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "three")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "four.c")
CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x0000011e)
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "four")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "five.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "five")
CHECK: DW_TAG_compile_unit [1] *
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "six.c")
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
CHECK: DW_TAG_subprogram [2]
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "six")
CHECK: .debug_line contents:
CHECK: file_names[ 1]:
CHECK: name: "main.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "one.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "two.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "three.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "four.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "five.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: file_names[ 1]:
CHECK: name: "six.c"
CHECK: dir_index: 0
CHECK: mod_time: 0x00000000
CHECK: length: 0x00000000
CHECK: .debug_pubnames contents:
CHECK: length = 0x00000017 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000044
CHECK: 0x0000002e "main"
CHECK: length = 0x00000016 version = 0x0002 unit_offset = 0x00000044 unit_size = 0x00000044
CHECK: 0x0000002e "one"
CHECK: length = 0x00000016 version = 0x0002 unit_offset = 0x00000088 unit_size = 0x00000044
CHECK: 0x0000002e "two"
CHECK: length = 0x00000018 version = 0x0002 unit_offset = 0x000000cc unit_size = 0x00000044
CHECK: 0x0000002e "three"
CHECK: length = 0x00000017 version = 0x0002 unit_offset = 0x00000110 unit_size = 0x00000044
CHECK: 0x0000002e "four"
CHECK: length = 0x00000017 version = 0x0002 unit_offset = 0x00000154 unit_size = 0x00000044
CHECK: 0x0000002e "five"
CHECK: length = 0x00000016 version = 0x0002 unit_offset = 0x00000198 unit_size = 0x00000044
CHECK: 0x0000002e "six"
CHECK: .apple_names contents:
CHECK: String: 0x00000091 "five"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x00000182
CHECK-NEXT: ]
CHECK: String: 0x0000009c "six"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x000001c6
CHECK-NEXT: ]
CHECK: String: 0x00000078 "three"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x000000fa
CHECK-NEXT: ]
CHECK: String: 0x0000006c "two"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x000000b6
CHECK-NEXT: ]
CHECK: String: 0x00000057 "main"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x0000002e
CHECK-NEXT: ]
CHECK: String: 0x00000085 "four"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x0000013e
CHECK-NEXT: ]
CHECK: String: 0x00000062 "one"
CHECK-NEXT: Data 0 [
CHECK-NEXT: Atom[0]: 0x00000072
CHECK-NEXT: ]

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DBGOriginalUUID</key>
<string>506AA50A-6B26-3B37-86D2-DC6EBD57B720</string>
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,22 @@
BCSymbolMap Version: 2.0
_two
_three
_four
_five
_six
LLVM version 3.9.0 (ssh://git@stash.sd.apple.com/devtools/clang.git c74ae34bd917b77f9c848bd599dfde2813fb509f)
main
main.c
/Volumes/Data/dev/BitcodeBuildTests/unit
one
one.c
two
two.c
three
three.c
four
four.c
five
five.c
six
six.c

Binary file not shown.

View File

@ -0,0 +1,17 @@
one
two
three
four
five
six
.str
Apple LLVM version 7.0.0 (clang-700.2.38.2)
main
main.c
/Users/steven/dev/alpena/tests/src
one.c
two.c
three.c
four.c
five.c
six.c

View File

@ -17,6 +17,7 @@ HELP: -num-threads=<n>
HELP: -o=<filename>
HELP: -oso-prepend-path=<path>
HELP: -papertrail
HELP: -symbol-map
HELP: -symtab
HELP: -toolchain
HELP: -update

View File

@ -20,6 +20,7 @@ add_llvm_tool(dsymutil
MachODebugMapParser.cpp
MachOUtils.cpp
NonRelocatableStringpool.cpp
SymbolMap.cpp
DEPENDS
intrinsics_gen

View File

@ -75,7 +75,7 @@ class DebugMapObject;
class DebugMap {
Triple BinaryTriple;
std::string BinaryPath;
std::vector<uint8_t> BinaryUUID;
using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>;
ObjectContainer Objects;
@ -89,8 +89,10 @@ class DebugMap {
///@}
public:
DebugMap(const Triple &BinaryTriple, StringRef BinaryPath)
: BinaryTriple(BinaryTriple), BinaryPath(BinaryPath) {}
DebugMap(const Triple &BinaryTriple, StringRef BinaryPath,
ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>())
: BinaryTriple(BinaryTriple), BinaryPath(BinaryPath),
BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {}
using const_iterator = ObjectContainer::const_iterator;
@ -113,6 +115,10 @@ public:
const Triple &getTriple() const { return BinaryTriple; }
const ArrayRef<uint8_t> getUUID() const {
return ArrayRef<uint8_t>(BinaryUUID);
}
StringRef getBinaryPath() const { return BinaryPath; }
void print(raw_ostream &OS) const;

View File

@ -1701,6 +1701,8 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
DWARFDataExtractor LineExtractor(
OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(),
OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize());
if (Options.Translator)
return Streamer->translateLineTable(LineExtractor, StmtOffset, Options);
Error Err = LineTable.parse(LineExtractor, &StmtOffset, OrigDwarf,
&Unit.getOrigUnit(), DWARFContext::dumpWarning);
@ -2245,17 +2247,16 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
if (Linker.Options.NoOutput)
continue;
if (LLVM_LIKELY(!Linker.Options.Update)) {
// FIXME: for compatibility with the classic dsymutil, we emit an empty
// line table for the unit, even if the unit doesn't actually exist in
// the DIE tree.
// FIXME: for compatibility with the classic dsymutil, we emit
// an empty line table for the unit, even if the unit doesn't
// actually exist in the DIE tree.
if (LLVM_LIKELY(!Linker.Options.Update) || Linker.Options.Translator)
Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext, Ranges, DMO);
Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO);
Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
} else {
Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
}
Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
if (Linker.Options.Update)
continue;
Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO);
Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
}
if (Linker.Options.NoOutput)
@ -2380,7 +2381,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
// This Dwarf string pool which is used for emission. It must be used
// serially as the order of calling getStringOffset matters for
// reproducibility.
OffsetsStringPool OffsetsStringPool;
OffsetsStringPool OffsetsStringPool(Options.Translator);
// ODR Contexts for the link.
DeclContextTree ODRContexts;
@ -2649,7 +2650,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
pool.wait();
}
return Options.NoOutput ? true : Streamer->finish(Map);
return Options.NoOutput ? true : Streamer->finish(Map, Options.Translator);
} // namespace dsymutil
bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,

View File

@ -124,11 +124,11 @@ bool DwarfStreamer::init(Triple TheTriple) {
return true;
}
bool DwarfStreamer::finish(const DebugMap &DM) {
bool DwarfStreamer::finish(const DebugMap &DM, SymbolMapTranslator &T) {
bool Result = true;
if (DM.getTriple().isOSDarwin() && !DM.getBinaryPath().empty() &&
Options.FileType == OutputFileType::Object)
Result = MachOUtils::generateDsymCompanion(DM, *MS, OutFile);
Result = MachOUtils::generateDsymCompanion(DM, T, *MS, OutFile);
else
MS->Finish();
return Result;
@ -577,6 +577,89 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
MS->EmitLabel(LineEndSym);
}
/// Copy the debug_line over to the updated binary while unobfuscating the file
/// names and directories.
void DwarfStreamer::translateLineTable(DataExtractor Data, uint32_t Offset,
LinkOptions &Options) {
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
StringRef Contents = Data.getData();
// We have to deconstruct the line table header, because it contains to
// length fields that will need to be updated when we change the length of
// the files and directories in there.
unsigned UnitLength = Data.getU32(&Offset);
unsigned UnitEnd = Offset + UnitLength;
MCSymbol *BeginLabel = MC->createTempSymbol();
MCSymbol *EndLabel = MC->createTempSymbol();
unsigned Version = Data.getU16(&Offset);
if (Version > 5) {
warn("Unsupported line table version: dropping contents and not "
"unobfsucating line table.");
return;
}
Asm->EmitLabelDifference(EndLabel, BeginLabel, 4);
Asm->OutStreamer->EmitLabel(BeginLabel);
Asm->emitInt16(Version);
LineSectionSize += 6;
MCSymbol *HeaderBeginLabel = MC->createTempSymbol();
MCSymbol *HeaderEndLabel = MC->createTempSymbol();
Asm->EmitLabelDifference(HeaderEndLabel, HeaderBeginLabel, 4);
Asm->OutStreamer->EmitLabel(HeaderBeginLabel);
Offset += 4;
LineSectionSize += 4;
uint32_t AfterHeaderLengthOffset = Offset;
// Skip to the directories.
Offset += (Version >= 4) ? 5 : 4;
unsigned OpcodeBase = Data.getU8(&Offset);
Offset += OpcodeBase - 1;
Asm->OutStreamer->EmitBytes(Contents.slice(AfterHeaderLengthOffset, Offset));
LineSectionSize += Offset - AfterHeaderLengthOffset;
// Offset points to the first directory.
while (const char *Dir = Data.getCStr(&Offset)) {
if (Dir[0] == 0)
break;
StringRef Translated = Options.Translator(Dir);
Asm->OutStreamer->EmitBytes(Translated);
Asm->emitInt8(0);
LineSectionSize += Translated.size() + 1;
}
Asm->emitInt8(0);
LineSectionSize += 1;
while (const char *File = Data.getCStr(&Offset)) {
if (File[0] == 0)
break;
StringRef Translated = Options.Translator(File);
Asm->OutStreamer->EmitBytes(Translated);
Asm->emitInt8(0);
LineSectionSize += Translated.size() + 1;
uint32_t OffsetBeforeLEBs = Offset;
Asm->EmitULEB128(Data.getULEB128(&Offset));
Asm->EmitULEB128(Data.getULEB128(&Offset));
Asm->EmitULEB128(Data.getULEB128(&Offset));
LineSectionSize += Offset - OffsetBeforeLEBs;
}
Asm->emitInt8(0);
LineSectionSize += 1;
Asm->OutStreamer->EmitLabel(HeaderEndLabel);
// Copy the actual line table program over.
Asm->OutStreamer->EmitBytes(Contents.slice(Offset, UnitEnd));
LineSectionSize += UnitEnd - Offset;
Asm->OutStreamer->EmitLabel(EndLabel);
Offset = UnitEnd;
}
static void emitSectionContents(const object::ObjectFile &Obj,
StringRef SecName, MCStreamer *MS) {
StringRef Contents;
@ -586,8 +669,10 @@ static void emitSectionContents(const object::ObjectFile &Obj,
}
void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj) {
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
emitSectionContents(Obj, "debug_line", MS);
if (!Options.Translator) {
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
emitSectionContents(Obj, "debug_line", MS);
}
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
emitSectionContents(Obj, "debug_loc", MS);

View File

@ -50,7 +50,7 @@ public:
bool init(Triple TheTriple);
/// Dump the file to the disk.
bool finish(const DebugMap &);
bool finish(const DebugMap &, SymbolMapTranslator &T);
AsmPrinter &getAsmPrinter() const { return *Asm; }
@ -104,6 +104,11 @@ public:
std::vector<DWARFDebugLine::Row> &Rows,
unsigned AdddressSize);
/// Copy the debug_line over to the updated binary while unobfuscating the
/// file names and directories.
void translateLineTable(DataExtractor LineData, uint32_t Offset,
LinkOptions &Options);
/// Copy over the debug sections that are not modified when updating.
void copyInvariantDebugSection(const object::ObjectFile &Obj);

View File

@ -10,8 +10,11 @@
#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
#include "SymbolMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/WithColor.h"
#include <string>
namespace llvm {
@ -60,6 +63,9 @@ struct LinkOptions {
/// -oso-prepend-path
std::string PrependPath;
/// Symbol map translator.
SymbolMapTranslator Translator;
LinkOptions() = default;
};

View File

@ -163,7 +163,8 @@ std::unique_ptr<DebugMap>
MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
StringRef BinaryPath) {
loadMainBinarySymbols(MainBinary);
Result = make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath);
ArrayRef<uint8_t> UUID = MainBinary.getUuid();
Result = make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID);
MainBinaryStrings = MainBinary.getStringTableData();
for (const SymbolRef &Symbol : MainBinary.symbols()) {
const DataRefImpl &DRI = Symbol.getRawDataRefImpl();

View File

@ -333,8 +333,8 @@ static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {
// Stream a dSYM companion binary file corresponding to the binary referenced
// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to
// \a OutFile and it must be using a MachObjectWriter object to do so.
bool generateDsymCompanion(const DebugMap &DM, MCStreamer &MS,
raw_fd_ostream &OutFile) {
bool generateDsymCompanion(const DebugMap &DM, SymbolMapTranslator &Translator,
MCStreamer &MS, raw_fd_ostream &OutFile) {
auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);
MCAssembler &MCAsm = ObjectStreamer.getAssembler();
auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter());
@ -443,7 +443,7 @@ bool generateDsymCompanion(const DebugMap &DM, MCStreamer &MS,
}
SmallString<0> NewSymtab;
NonRelocatableStringpool NewStrings;
NonRelocatableStringpool NewStrings(Translator);
unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
unsigned NumSyms = 0;
uint64_t NewStringsSize = 0;

View File

@ -9,8 +9,11 @@
#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
#include "SymbolMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include <string>
namespace llvm {
@ -38,8 +41,8 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
StringRef OutputFileName, const LinkOptions &,
StringRef SDKPath);
bool generateDsymCompanion(const DebugMap &DM, MCStreamer &MS,
raw_fd_ostream &OutFile);
bool generateDsymCompanion(const DebugMap &DM, SymbolMapTranslator &Translator,
MCStreamer &MS, raw_fd_ostream &OutFile);
std::string getArchName(StringRef Arch);
} // namespace MachOUtils

View File

@ -16,6 +16,8 @@ DwarfStringPoolEntryRef NonRelocatableStringpool::getEntry(StringRef S) {
if (S.empty() && !Strings.empty())
return EmptyString;
if (Translator)
S = Translator(S);
auto I = Strings.insert({S, DwarfStringPoolEntry()});
auto &Entry = I.first->second;
if (I.second || !Entry.isIndexed()) {
@ -29,6 +31,10 @@ DwarfStringPoolEntryRef NonRelocatableStringpool::getEntry(StringRef S) {
StringRef NonRelocatableStringpool::internString(StringRef S) {
DwarfStringPoolEntry Entry{nullptr, 0, DwarfStringPoolEntry::NotIndexed};
if (Translator)
S = Translator(S);
auto InsertResult = Strings.insert({S, Entry});
return InsertResult.first->getKey();
}

View File

@ -10,6 +10,8 @@
#ifndef LLVM_TOOLS_DSYMUTIL_NONRELOCATABLESTRINGPOOL_H
#define LLVM_TOOLS_DSYMUTIL_NONRELOCATABLESTRINGPOOL_H
#include "SymbolMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
@ -32,7 +34,9 @@ public:
/// order.
using MapTy = StringMap<DwarfStringPoolEntry, BumpPtrAllocator>;
NonRelocatableStringpool() {
NonRelocatableStringpool(
SymbolMapTranslator Translator = SymbolMapTranslator())
: Translator(Translator) {
// Legacy dsymutil puts an empty string at the start of the line table.
EmptyString = getEntry("");
}
@ -62,6 +66,7 @@ private:
uint32_t CurrentEndOffset = 0;
unsigned NumEntries = 0;
DwarfStringPoolEntryRef EmptyString;
SymbolMapTranslator Translator;
};
/// Helper for making strong types.

View File

@ -0,0 +1,162 @@
//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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 = BCSymbolMapPath.str();
}
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

View File

@ -0,0 +1,54 @@
//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
namespace llvm {
namespace dsymutil {
class DebugMap;
/// Callable class to unobfuscate strings based on a BCSymbolMap.
class SymbolMapTranslator {
public:
SymbolMapTranslator() : MangleNames(false) {}
SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings,
bool MangleNames)
: UnobfuscatedStrings(std::move(UnobfuscatedStrings)),
MangleNames(MangleNames) {}
StringRef operator()(StringRef Input);
operator bool() const { return !UnobfuscatedStrings.empty(); }
private:
std::vector<std::string> UnobfuscatedStrings;
bool MangleNames;
};
/// Class to initialize SymbolMapTranslators from a BCSymbolMap.
class SymbolMapLoader {
public:
SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {}
SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const;
private:
const std::string SymbolMap;
};
} // namespace dsymutil
} // namespace llvm
#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H

View File

@ -59,6 +59,8 @@ static opt<std::string>
OutputFileOpt("o",
desc("Specify the output file. default: <input file>.dwarf"),
value_desc("filename"), cat(DsymCategory));
static alias OutputFileOptA("out", desc("Alias for -o"),
aliasopt(OutputFileOpt));
static opt<std::string> OsoPrependPath(
"oso-prepend-path",
@ -100,6 +102,11 @@ static opt<bool> Update(
init(false), cat(DsymCategory));
static alias UpdateA("u", desc("Alias for --update"), aliasopt(Update));
static opt<std::string> SymbolMap(
"symbol-map",
desc("Updates the existing dSYMs inplace using symbol map specified."),
value_desc("bcsymbolmap"), cat(DsymCategory));
static cl::opt<AccelTableKind> AcceleratorTable(
"accelerator", cl::desc("Output accelerator tables."),
cl::values(clEnumValN(AccelTableKind::Default, "Default",
@ -273,8 +280,11 @@ static bool verify(llvm::StringRef OutputFile, llvm::StringRef Arch) {
}
static Expected<std::string> getOutputFileName(llvm::StringRef InputFile) {
if (OutputFileOpt == "-")
return OutputFileOpt;
// When updating, do in place replacement.
if (OutputFileOpt.empty() && Update)
if (OutputFileOpt.empty() && (Update || !SymbolMap.empty()))
return InputFile;
// If a flat dSYM has been requested, things are pretty simple.
@ -325,6 +335,9 @@ static Expected<LinkOptions> getOptions() {
Options.PrependPath = OsoPrependPath;
Options.TheAccelTableKind = AcceleratorTable;
if (!SymbolMap.empty())
Options.Update = true;
if (Assembly)
Options.FileType = OutputFileType::Assembly;
@ -443,6 +456,13 @@ int main(int argc, char **argv) {
return 1;
}
if (InputFiles.size() > 1 && !SymbolMap.empty() &&
!llvm::sys::fs::is_directory(SymbolMap)) {
WithColor::error() << "when unobfuscating multiple files, --symbol-map "
<< "needs to point to a directory.\n";
return 1;
}
if (getenv("RC_DEBUG_OPTIONS"))
PaperTrailWarnings = true;
@ -457,6 +477,8 @@ int main(int argc, char **argv) {
return 1;
}
SymbolMapLoader SymMapLoader(SymbolMap);
for (auto &InputFile : *InputsOrErr) {
// Dump the symbol table for each input file and requested arch
if (DumpStab) {
@ -511,6 +533,9 @@ int main(int argc, char **argv) {
if (DumpDebugMap)
continue;
if (!SymbolMap.empty())
OptionsOrErr->Translator = SymMapLoader.Load(InputFile, *Map);
if (Map->begin() == Map->end())
WithColor::warning()
<< "no debug symbols in executable (-arch "