Skip to content

Commit 30a56da

Browse files
Merge pull request #10460 from adrian-prantl/cherry-pick-swift-release-6.2-dsymutil-Avoid-copying-binary-swiftmodules-built-from-textual
[Cherry-pick into swift/release/6.2] [dsymutil] Avoid copying binary swiftmodules built from textual
2 parents 2247eb3 + 47f151f commit 30a56da

10 files changed

+264
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# RUN: dsymutil -verbose -oso-prepend-path=%p -y -o %t.dSYM %s | FileCheck %s
2+
#
3+
# RUN: dsymutil --linker parallel -verbose -oso-prepend-path=%p -y %s -o %t-parallel.dSYM | FileCheck %s
4+
#
5+
# To regenerate:
6+
# echo ''>I.swift
7+
# echo ''>B.swift
8+
# echo 'import I'>main.swift
9+
# xcrun swiftc -emit-module-interface-path I.swiftinterface -enable-library-evolution I.swift
10+
# xcrun swiftc -emit-module-path B.swiftmodule B.swift -Xfrontend -no-serialize-debugging-options
11+
# xcrun swiftc -explicit-module-build main.swift -I. -module-cache-path cache -g -Xfrontend -no-serialize-debugging-options
12+
# output is "B.swiftmodule" and "cache/I*.swiftmodule"
13+
#
14+
# CHECK-NOT: Skipping compiled textual Swift interface: {{.*}}/Inputs/Binary.swiftmodule
15+
# CHECK: Skipping compiled textual Swift interface: {{.*}}/Inputs/FromInterface.swiftmodule
16+
17+
#
18+
---
19+
triple: 'arm64-apple-darwin'
20+
objects:
21+
- filename: '../Inputs/Binary.swiftmodule'
22+
timestamp: 0
23+
type: 50
24+
symbols: []
25+
- filename: '../Inputs/FromInterface.swiftmodule'
26+
timestamp: 0
27+
type: 50
28+
symbols: []
29+
...
Binary file not shown.
Binary file not shown.

llvm/test/tools/dsymutil/yaml-object-address-rewrite.test

+3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
# CHECK-NEXT: objects:
1313
# CHECK-NEXT: filename:{{.*}}/Inputs/basic1.macho.x86_64.o
1414
# CHECK-NEXT: timestamp: 0
15+
# CHECK-NEXT: type: 102
1516
# CHECK-NEXT: symbols:
1617
# CHECK-NEXT: sym: _main, objAddr: 0x0, binAddr: 0x100000EA0, size: 0x24
1718
# CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic2.macho.x86_64.o)'
1819
# CHECK-NEXT: timestamp: 0
20+
# CHECK-NEXT: type: 102
1921
# CHECK-NEXT: symbols:
2022
# CHECK-DAG: sym: _foo, objAddr: 0x20, binAddr: 0x100000ED0, size: 0x50
2123
# CHECK-DAG: sym: _private_int, objAddr: 0x560, binAddr: 0x100001004, size: 0x0
@@ -24,6 +26,7 @@
2426
# CHECK-NOT: { sym:
2527
# CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic3.macho.x86_64.o)'
2628
# CHECK-NEXT: timestamp: 0
29+
# CHECK-NEXT: type: 102
2730
# CHECK-NEXT: symbols:
2831
# CHECK-DAG: sym: _val, binAddr: 0x100001008, size: 0x0
2932
# CHECK-DAG: sym: _bar, objAddr: 0x20, binAddr: 0x100000F40, size: 0x50

llvm/tools/dsymutil/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set(LLVM_LINK_COMPONENTS
77
AllTargetsDescs
88
AllTargetsInfos
99
AsmPrinter
10+
BitReader
11+
BitStreamReader
1012
CodeGen
1113
CodeGenTypes
1214
DWARFLinker
@@ -32,6 +34,7 @@ add_llvm_tool(dsymutil
3234
MachOUtils.cpp
3335
Reproducer.cpp
3436
RelocationMap.cpp
37+
SwiftModule.cpp
3538

3639
DEPENDS
3740
intrinsics_gen

llvm/tools/dsymutil/DebugMap.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,13 @@ namespace yaml {
161161

162162
// Normalize/Denormalize between YAML and a DebugMapObject.
163163
struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
164-
YamlDMO(IO &io) { Timestamp = 0; }
164+
YamlDMO(IO &io) {}
165165
YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
166166
dsymutil::DebugMapObject denormalize(IO &IO);
167167

168168
std::string Filename;
169-
int64_t Timestamp;
169+
int64_t Timestamp = 0;
170+
uint8_t Type = MachO::N_OSO;
170171
std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
171172
};
172173

@@ -183,6 +184,7 @@ void MappingTraits<dsymutil::DebugMapObject>::mapping(
183184
MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
184185
io.mapRequired("filename", Norm->Filename);
185186
io.mapOptional("timestamp", Norm->Timestamp);
187+
io.mapOptional("type", Norm->Type);
186188
io.mapRequired("symbols", Norm->Entries);
187189
}
188190

@@ -236,6 +238,7 @@ MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
236238
IO &io, dsymutil::DebugMapObject &Obj) {
237239
Filename = Obj.Filename;
238240
Timestamp = sys::toTimeT(Obj.getTimestamp());
241+
Type = Obj.getType();
239242
Entries.reserve(Obj.Symbols.size());
240243
for (auto &Entry : Obj.Symbols)
241244
Entries.push_back(
@@ -286,7 +289,6 @@ MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
286289
}
287290
}
288291

289-
uint8_t Type = MachO::N_OSO;
290292
if (Path.ends_with(".dylib")) {
291293
// FIXME: find a more resilient way
292294
Type = MachO::N_LIB;

llvm/tools/dsymutil/DwarfLinkerForBinary.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "BinaryHolder.h"
1111
#include "DebugMap.h"
1212
#include "MachOUtils.h"
13+
#include "SwiftModule.h"
1314
#include "dsymutil.h"
1415
#include "llvm/ADT/ArrayRef.h"
1516
#include "llvm/ADT/DenseMap.h"
@@ -783,6 +784,21 @@ bool DwarfLinkerForBinary::linkImpl(
783784
reportWarning("Could not open '" + File + "'");
784785
continue;
785786
}
787+
auto FromInterfaceOrErr =
788+
IsBuiltFromSwiftInterface((*ErrorOrMem)->getBuffer());
789+
if (!FromInterfaceOrErr) {
790+
reportWarning("Could not parse binary Swift module: " +
791+
toString(FromInterfaceOrErr.takeError()),
792+
Obj->getObjectFilename());
793+
// Only skip swiftmodules that could be parsed and are
794+
// positively identified as textual.
795+
} else if (*FromInterfaceOrErr) {
796+
if (Options.Verbose)
797+
outs() << "Skipping compiled textual Swift interface: "
798+
<< Obj->getObjectFilename() << "\n";
799+
continue;
800+
}
801+
786802
sys::fs::file_status Stat;
787803
if (auto Err = sys::fs::status(File, Stat)) {
788804
reportWarning(Err.message());

llvm/tools/dsymutil/RelocationMap.h

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct SymbolMapping {
3737
std::optional<yaml::Hex64> ObjectAddress;
3838
yaml::Hex64 BinaryAddress;
3939
yaml::Hex32 Size;
40+
yaml::Hex8 Type;
4041

4142
SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
4243
uint32_t Size)

llvm/tools/dsymutil/SwiftModule.cpp

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//===- tools/dsymutil/SwiftModule.cpp -------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Bitcode/BitcodeReader.h"
10+
#include "llvm/Bitcode/LLVMBitCodes.h"
11+
#include "llvm/Bitstream/BitCodes.h"
12+
#include "llvm/Bitstream/BitstreamReader.h"
13+
14+
namespace {
15+
// Copied from swift/lib/Serialization/ModuleFormat.h
16+
constexpr unsigned char SWIFTMODULE_SIGNATURE[] = {0xE2, 0x9C, 0xA8, 0x0E};
17+
constexpr uint16_t expectedMajorVersion = 0;
18+
constexpr unsigned MODULE_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID;
19+
constexpr unsigned CONTROL_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + 1;
20+
constexpr unsigned METADATA = 1;
21+
constexpr unsigned OPTIONS_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + 8;
22+
constexpr unsigned IS_BUILT_FROM_INTERFACE = 11;
23+
24+
llvm::Error checkModuleSignature(llvm::BitstreamCursor &cursor,
25+
llvm::ArrayRef<unsigned char> signature) {
26+
for (unsigned char byte : signature) {
27+
if (cursor.AtEndOfStream())
28+
return llvm::createStringError("malformed bitstream");
29+
llvm::Expected<llvm::SimpleBitstreamCursor::word_t> maybeRead =
30+
cursor.Read(8);
31+
if (!maybeRead)
32+
return maybeRead.takeError();
33+
if (maybeRead.get() != byte)
34+
return llvm::createStringError("malformed bitstream");
35+
}
36+
return llvm::Error::success();
37+
}
38+
39+
llvm::Error enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor,
40+
unsigned ID) {
41+
llvm::Expected<llvm::BitstreamEntry> maybeNext = cursor.advance();
42+
if (!maybeNext)
43+
return maybeNext.takeError();
44+
llvm::BitstreamEntry next = maybeNext.get();
45+
46+
if (next.Kind != llvm::BitstreamEntry::SubBlock)
47+
return llvm::createStringError("malformed bitstream");
48+
49+
if (next.ID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
50+
if (cursor.SkipBlock())
51+
return llvm::createStringError("malformed bitstream");
52+
return enterTopLevelModuleBlock(cursor, ID);
53+
}
54+
55+
if (next.ID != ID)
56+
return llvm::createStringError("malformed bitstream");
57+
58+
if (llvm::Error Err = cursor.EnterSubBlock(ID))
59+
return Err;
60+
61+
return llvm::Error::success();
62+
}
63+
64+
llvm::Expected<bool>
65+
readOptionsBlock(llvm::BitstreamCursor &cursor,
66+
llvm::SmallVectorImpl<uint64_t> &scratch) {
67+
bool is_built_from_interface = false;
68+
while (!cursor.AtEndOfStream()) {
69+
llvm::Expected<llvm::BitstreamEntry> maybeEntry = cursor.advance();
70+
if (!maybeEntry)
71+
return maybeEntry.takeError();
72+
73+
llvm::BitstreamEntry entry = maybeEntry.get();
74+
if (entry.Kind == llvm::BitstreamEntry::EndBlock)
75+
break;
76+
77+
if (entry.Kind == llvm::BitstreamEntry::Error)
78+
return llvm::createStringError("malformed bitstream");
79+
80+
if (entry.Kind == llvm::BitstreamEntry::SubBlock) {
81+
if (cursor.SkipBlock())
82+
return llvm::createStringError("malformed bitstream");
83+
continue;
84+
}
85+
86+
scratch.clear();
87+
llvm::StringRef blobData;
88+
llvm::Expected<unsigned> maybeKind =
89+
cursor.readRecord(entry.ID, scratch, &blobData);
90+
if (!maybeKind)
91+
return maybeKind.takeError();
92+
unsigned kind = maybeKind.get();
93+
switch (kind) {
94+
case IS_BUILT_FROM_INTERFACE:
95+
is_built_from_interface = true;
96+
continue;
97+
default:
98+
continue;
99+
}
100+
}
101+
return is_built_from_interface;
102+
}
103+
104+
llvm::Expected<bool>
105+
parseControlBlock(llvm::BitstreamCursor &cursor,
106+
llvm::SmallVectorImpl<uint64_t> &scratch) {
107+
// The control block is malformed until we've at least read a major version
108+
// number.
109+
bool versionSeen = false;
110+
111+
while (!cursor.AtEndOfStream()) {
112+
llvm::Expected<llvm::BitstreamEntry> maybeEntry = cursor.advance();
113+
if (!maybeEntry)
114+
return maybeEntry.takeError();
115+
116+
llvm::BitstreamEntry entry = maybeEntry.get();
117+
if (entry.Kind == llvm::BitstreamEntry::EndBlock)
118+
break;
119+
120+
if (entry.Kind == llvm::BitstreamEntry::Error)
121+
return llvm::createStringError("malformed bitstream");
122+
123+
if (entry.Kind == llvm::BitstreamEntry::SubBlock) {
124+
if (entry.ID == OPTIONS_BLOCK_ID) {
125+
if (llvm::Error Err = cursor.EnterSubBlock(OPTIONS_BLOCK_ID))
126+
return Err;
127+
128+
return readOptionsBlock(cursor, scratch);
129+
} else {
130+
// Unknown metadata sub-block, possibly for use by a future version of
131+
// the module format.
132+
if (cursor.SkipBlock())
133+
return llvm::createStringError("malformed bitstream");
134+
}
135+
continue;
136+
}
137+
138+
scratch.clear();
139+
llvm::StringRef blobData;
140+
llvm::Expected<unsigned> maybeKind =
141+
cursor.readRecord(entry.ID, scratch, &blobData);
142+
if (!maybeKind)
143+
return maybeKind.takeError();
144+
145+
unsigned kind = maybeKind.get();
146+
if (kind == METADATA) {
147+
if (versionSeen)
148+
return llvm::createStringError("multiple metadata blocks");
149+
150+
uint16_t versionMajor = scratch[0];
151+
if (versionMajor != expectedMajorVersion)
152+
return llvm::createStringError("unsupported module version");
153+
154+
versionSeen = true;
155+
}
156+
}
157+
return llvm::createStringError("could not find control block");
158+
}
159+
160+
} // namespace
161+
162+
llvm::Expected<bool> IsBuiltFromSwiftInterface(llvm::StringRef data) {
163+
llvm::BitstreamCursor cursor(data);
164+
if (llvm::Error Err = checkModuleSignature(cursor, SWIFTMODULE_SIGNATURE))
165+
return llvm::joinErrors(
166+
llvm::createStringError("could not check signature"), std::move(Err));
167+
if (llvm::Error Err = enterTopLevelModuleBlock(cursor, MODULE_BLOCK_ID))
168+
return llvm::joinErrors(
169+
llvm::createStringError("could not enter top level block"),
170+
std::move(Err));
171+
172+
llvm::BitstreamEntry topLevelEntry;
173+
llvm::SmallVector<uint64_t, 32> scratch;
174+
175+
while (!cursor.AtEndOfStream()) {
176+
llvm::Expected<llvm::BitstreamEntry> maybeEntry =
177+
cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
178+
if (!maybeEntry)
179+
return maybeEntry.takeError();
180+
181+
topLevelEntry = maybeEntry.get();
182+
if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock)
183+
break;
184+
185+
if (topLevelEntry.ID == CONTROL_BLOCK_ID) {
186+
if (llvm::Error Err = cursor.EnterSubBlock(CONTROL_BLOCK_ID))
187+
return Err;
188+
return parseControlBlock(cursor, scratch);
189+
}
190+
}
191+
return llvm::createStringError("no control block found");
192+
}

llvm/tools/dsymutil/SwiftModule.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//===- tools/dsymutil/SwiftModule.h ---------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#ifndef LLVM_TOOLS_DSYMUTIL_SWIFTMODULE_H
9+
#define LLVM_TOOLS_DSYMUTIL_SWIFTMODULE_H
10+
11+
#include "llvm/Support/Error.h"
12+
13+
llvm::Expected<bool> IsBuiltFromSwiftInterface(llvm::StringRef data);
14+
15+
#endif

0 commit comments

Comments
 (0)